Skip to content

Commit 734ffc8

Browse files
authored
Stop inlining large TestData (#5647) (#6292)
1 parent 3bf6c68 commit 734ffc8

File tree

4 files changed

+69
-26
lines changed

4 files changed

+69
-26
lines changed

src/WebJobs.Script.WebHost/Extensions/FunctionMetadataExtensions.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,18 @@ private static async Task<string> GetTestData(string testDataPath, ScriptHostCon
125125
await FileUtility.WriteAsync(testDataPath, string.Empty);
126126
}
127127

128-
return await FileUtility.ReadAsync(testDataPath);
128+
string data = await FileUtility.ReadAsync(testDataPath);
129+
130+
// We avoid inlining test data beyond the specified length. We do this to
131+
// provide back compat for the majority of cases. In all other cases, the caller
132+
// is expected to follow TestDataHref to retrieve the data.
133+
bool testDataCapEnabled = (Environment.GetEnvironmentVariable(EnvironmentSettingNames.TestDataCapEnabled) ?? "1") == "1";
134+
if (data.Length > ScriptConstants.MaxTestDataInlineStringLength && testDataCapEnabled)
135+
{
136+
return null;
137+
}
138+
139+
return data;
129140
}
130141

131142
internal static Uri GetFunctionInvokeUrlTemplate(string baseUrl, FunctionMetadata functionMetadata, string routePrefix)

src/WebJobs.Script/EnvironmentSettingNames.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public static class EnvironmentSettingNames
3030
public const string SkipSslValidation = "SCM_SKIP_SSL_VALIDATION";
3131
public const string CoreToolsEnvironment = "FUNCTIONS_CORETOOLS_ENVIRONMENT";
3232
public const string AzureWebsiteArmCacheEnabled = "WEBSITE_FUNCTIONS_ARMCACHE_ENABLED";
33+
public const string TestDataCapEnabled = "WEBSITE_FUNCTIONS_TESTDATA_CAP_ENABLED";
3334

3435
/// <summary>
3536
/// Environment variable dynamically set by the platform when it is safe to

src/WebJobs.Script/ScriptConstants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,5 +109,6 @@ public static class ScriptConstants
109109
/// for settriggers calls. If we raise that limit there, we should raise here as well.
110110
/// </summary>
111111
public const int MaxTriggersStringLength = 204800;
112+
public const int MaxTestDataInlineStringLength = 4 * 1024;
112113
}
113114
}

test/WebJobs.Script.Tests/Management/WebFunctionsManagerTests.cs

Lines changed: 55 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -35,37 +35,63 @@ public WebFunctionsManagerTests()
3535

3636
_hostConfig = new ScriptHostConfiguration
3737
{
38-
RootScriptPath = @"x:\root\site\wwwroot",
38+
RootScriptPath = @"x:\root",
3939
IsSelfHost = false,
4040
RootLogPath = @"x:\root\LogFiles\Application\Functions",
41-
TestDataPath = @"x:\root\data\functions\sampledata"
41+
TestDataPath = @"x:\root\data"
4242
};
4343
_hostConfig.HostConfig.HostId = "testhostid123";
4444

4545
HostNameProvider.Reset();
4646
}
4747

48-
[Fact]
49-
public async Task ReadFunctionsMetadataSucceeds()
48+
[Theory]
49+
[InlineData(true)]
50+
[InlineData(false)]
51+
public async Task ReadFunctionsMetadataSucceeds(bool testDataCapEnabled)
5052
{
51-
// Setup
52-
var fileSystem = CreateFileSystem(_hostConfig);
53-
var loggerProvider = new TestLoggerProvider();
54-
var loggerFactory = new LoggerFactory();
55-
loggerFactory.AddProvider(loggerProvider);
56-
57-
var contentBuilder = new StringBuilder();
58-
var httpClient = CreateHttpClient(contentBuilder);
59-
var webManager = new WebFunctionsManager(_hostConfig, loggerFactory);
60-
61-
FileUtility.Instance = fileSystem;
62-
var functions = await webManager.GetFunctionsMetadata();
63-
var jsFunctions = functions.Where(funcMetadata => funcMetadata.Language == ScriptType.Javascript.ToString()).ToList();
64-
var pytonFunctions = functions.Where(funcMetadata => funcMetadata.Language == ScriptType.Python.ToString()).ToList();
65-
66-
Assert.Equal(3, functions.Count());
67-
Assert.Equal(2, jsFunctions.Count());
68-
Assert.Equal(1, pytonFunctions.Count());
53+
var env = new Dictionary<string, string>();
54+
if (!testDataCapEnabled)
55+
{
56+
env.Add(EnvironmentSettingNames.TestDataCapEnabled, "0");
57+
}
58+
var envScope = new TestScopedEnvironmentVariable(env);
59+
using (envScope)
60+
{
61+
// Setup
62+
var fileSystem = CreateFileSystem(_hostConfig);
63+
var loggerProvider = new TestLoggerProvider();
64+
var loggerFactory = new LoggerFactory();
65+
loggerFactory.AddProvider(loggerProvider);
66+
67+
var contentBuilder = new StringBuilder();
68+
var httpClient = CreateHttpClient(contentBuilder);
69+
var webManager = new WebFunctionsManager(_hostConfig, loggerFactory);
70+
71+
FileUtility.Instance = fileSystem;
72+
var metadata = (await webManager.GetFunctionsMetadata()).ToArray();
73+
74+
Assert.Equal(3, metadata.Count());
75+
Assert.Equal(2, metadata.Count(p => p.Language == ScriptType.Javascript.ToString()));
76+
Assert.Equal(1, metadata.Count(p => p.Language == ScriptType.Python.ToString()));
77+
78+
Assert.Equal("https://localhost/api/vfs/data/function1.dat", metadata[0].TestDataHref.AbsoluteUri);
79+
Assert.Equal("https://localhost/api/vfs/data/function2.dat", metadata[1].TestDataHref.AbsoluteUri);
80+
Assert.Equal("https://localhost/api/vfs/data/function3.dat", metadata[2].TestDataHref.AbsoluteUri);
81+
82+
Assert.Equal("Test Data 1", metadata[0].TestData);
83+
Assert.Equal("Test Data 2", metadata[1].TestData);
84+
85+
if (testDataCapEnabled)
86+
{
87+
// TestData size is capped by default
88+
Assert.Null(metadata[2].TestData);
89+
}
90+
else
91+
{
92+
Assert.Equal(ScriptConstants.MaxTestDataInlineStringLength + 1, metadata[2].TestData.Length);
93+
}
94+
}
6995
}
7096

7197
[Theory]
@@ -236,6 +262,10 @@ private static IFileSystem CreateFileSystem(ScriptHostConfiguration hostConfig)
236262
]
237263
}";
238264

265+
string testData1 = "Test Data 1";
266+
string testData2 = "Test Data 2";
267+
string testData3 = TestHelpers.NewRandomString(ScriptConstants.MaxTestDataInlineStringLength + 1);
268+
239269
fileBase.Setup(f => f.Exists(Path.Combine(rootScriptPath, @"function1\function.json"))).Returns(true);
240270
fileBase.Setup(f => f.Exists(Path.Combine(rootScriptPath, @"function1\main.py"))).Returns(true);
241271
fileBase.Setup(f => f.ReadAllText(Path.Combine(rootScriptPath, @"function1\function.json"))).Returns(function1);
@@ -245,7 +275,7 @@ private static IFileSystem CreateFileSystem(ScriptHostConfiguration hostConfig)
245275
});
246276
fileBase.Setup(f => f.Open(Path.Combine(testDataPath, "function1.dat"), It.IsAny<FileMode>(), It.IsAny<FileAccess>(), It.IsAny<FileShare>())).Returns(() =>
247277
{
248-
return new MemoryStream(Encoding.UTF8.GetBytes(function1));
278+
return new MemoryStream(Encoding.UTF8.GetBytes(testData1));
249279
});
250280

251281
fileBase.Setup(f => f.Exists(Path.Combine(rootScriptPath, @"function2\function.json"))).Returns(true);
@@ -257,7 +287,7 @@ private static IFileSystem CreateFileSystem(ScriptHostConfiguration hostConfig)
257287
});
258288
fileBase.Setup(f => f.Open(Path.Combine(testDataPath, "function2.dat"), It.IsAny<FileMode>(), It.IsAny<FileAccess>(), It.IsAny<FileShare>())).Returns(() =>
259289
{
260-
return new MemoryStream(Encoding.UTF8.GetBytes(function1));
290+
return new MemoryStream(Encoding.UTF8.GetBytes(testData2));
261291
});
262292

263293
fileBase.Setup(f => f.Exists(Path.Combine(rootScriptPath, @"function3\function.json"))).Returns(true);
@@ -269,7 +299,7 @@ private static IFileSystem CreateFileSystem(ScriptHostConfiguration hostConfig)
269299
});
270300
fileBase.Setup(f => f.Open(Path.Combine(testDataPath, "function3.dat"), It.IsAny<FileMode>(), It.IsAny<FileAccess>(), It.IsAny<FileShare>())).Returns(() =>
271301
{
272-
return new MemoryStream(Encoding.UTF8.GetBytes(function1));
302+
return new MemoryStream(Encoding.UTF8.GetBytes(testData3));
273303
});
274304

275305
return fileSystem.Object;

0 commit comments

Comments
 (0)