Skip to content

Commit 4a1d58f

Browse files
authored
improving failure logging for e2e tests (#7154)
1 parent 67907cf commit 4a1d58f

File tree

7 files changed

+156
-85
lines changed

7 files changed

+156
-85
lines changed

test/CSharpPrecompiledTestProjects/AssemblyLoadContextRace/Function1.cs

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,38 +15,48 @@ public static class Function1
1515
[FunctionName("Function1")]
1616
public static IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req)
1717
{
18-
var resetEvent = new ManualResetEvent(false);
18+
try
19+
{
20+
var resetEvent = new ManualResetEvent(false);
1921

20-
// First, force Newtonsoft to load on many threads, which induces the race
21-
var context = AssemblyLoadContext.GetLoadContext(typeof(Function1).Assembly);
22+
// First, force Newtonsoft to load on many threads, which induces the race
23+
var context = AssemblyLoadContext.GetLoadContext(typeof(Function1).Assembly);
2224

23-
void LoadType()
24-
{
25-
var assembly = context.LoadFromAssemblyName(new AssemblyName("Newtonsoft.Json, Version=12.0.3.0"));
26-
}
25+
void LoadType()
26+
{
27+
var assembly = context.LoadFromAssemblyName(new AssemblyName("Newtonsoft.Json, Version=12.0.3.0"));
28+
}
2729

28-
List<Thread> threads = new List<Thread>();
30+
List<Thread> threads = new List<Thread>();
2931

30-
for (int i = 0; i < 100; i++)
31-
{
32-
Thread t = new Thread(LoadType);
33-
threads.Add(t);
34-
t.Start();
35-
}
32+
for (int i = 0; i < 100; i++)
33+
{
34+
Thread t = new Thread(LoadType);
35+
threads.Add(t);
36+
t.Start();
37+
}
3638

37-
foreach (Thread t in threads)
38-
{
39-
t.Join();
40-
}
39+
foreach (Thread t in threads)
40+
{
41+
t.Join();
42+
}
4143

42-
// Now, make sure the assemblies match, signifying that the race was fixed and we
43-
// always load the host's version.
44-
var functionAssembly = context.LoadFromAssemblyName(new AssemblyName("Newtonsoft.Json, Version=12.0.3.0"));
45-
var defaultAssembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName("Newtonsoft.Json, Version=12.0.3.0"));
44+
// Now, make sure the assemblies match, signifying that the race was fixed and we
45+
// always load the host's version.
46+
var functionAssembly = context.LoadFromAssemblyName(new AssemblyName("Newtonsoft.Json, Version=12.0.3.0"));
47+
var defaultAssembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName("Newtonsoft.Json, Version=12.0.3.0"));
4648

47-
if (!Equals(functionAssembly, defaultAssembly))
49+
if (!Equals(functionAssembly, defaultAssembly))
50+
{
51+
throw new InvalidOperationException("The FunctionAssemblyLoadContext Newtonsoft.Json assembly is not the same as the default AssemblyLoadContext assembly.");
52+
}
53+
}
54+
catch (Exception ex)
4855
{
49-
throw new InvalidOperationException();
56+
return new ObjectResult(ex.ToString())
57+
{
58+
StatusCode = 500
59+
};
5060
}
5161

5262
return new OkResult();

test/CSharpPrecompiledTestProjects/MultipleDependencyVersions/MultipleDependencyVersions.cs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,24 @@ public static class MultipleDependencyVersions
1212
public static IActionResult Run(
1313
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req)
1414
{
15-
// The host uses version 5.5 of this assembly, but the deps.json says that the app
16-
// should use 5.6.
17-
Type t55 = Dependency55.TypeGetter.ReturnSecurityKeyType();
18-
Type t56 = Dependency56.TypeGetter.ReturnSecurityKeyType();
15+
try
16+
{
17+
// The host uses version 5.5 of this assembly, but the deps.json says that the app
18+
// should use 5.6.
19+
Type t55 = Dependency55.TypeGetter.ReturnSecurityKeyType();
20+
Type t56 = Dependency56.TypeGetter.ReturnSecurityKeyType();
1921

20-
if (!Equals(t55, t56) || !Equals(t55.Assembly, t56.Assembly))
22+
if (!Equals(t55, t56) || !Equals(t55.Assembly, t56.Assembly))
23+
{
24+
throw new InvalidOperationException($"{t55.FullName} does not equal {t56.FullName}.");
25+
}
26+
}
27+
catch (Exception ex)
2128
{
22-
throw new InvalidOperationException();
29+
return new ObjectResult(ex.ToString())
30+
{
31+
StatusCode = 500
32+
};
2333
}
2434

2535
return new OkResult();

test/CSharpPrecompiledTestProjects/NativeDependencyNoRuntimes/NativeDependencyNoRuntimes.cs

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,36 @@ public async Task<IActionResult> Run(
2626
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req)
2727
{
2828
// Issue a query against Cosmos that forces a native assembly to load.
29-
30-
string cosmosConnection = _config.GetConnectionString("CosmosDB");
31-
var builder = new DbConnectionStringBuilder()
29+
try
3230
{
33-
ConnectionString = cosmosConnection
34-
};
31+
string cosmosConnection = _config.GetConnectionString("CosmosDB");
32+
var builder = new DbConnectionStringBuilder()
33+
{
34+
ConnectionString = cosmosConnection
35+
};
3536

36-
builder.TryGetValue("AccountEndpoint", out object dbUri);
37-
builder.TryGetValue("AccountKey", out object dbKey);
37+
builder.TryGetValue("AccountEndpoint", out object dbUri);
38+
builder.TryGetValue("AccountKey", out object dbKey);
3839

39-
var client = new DocumentClient(new Uri(dbUri.ToString()), dbKey.ToString());
40-
Uri collUri = UriFactory.CreateDocumentCollectionUri("ItemDb", "ItemCollection");
40+
var client = new DocumentClient(new Uri(dbUri.ToString()), dbKey.ToString());
41+
Uri collUri = UriFactory.CreateDocumentCollectionUri("ItemDb", "ItemCollection");
4142

42-
var options = new FeedOptions
43-
{
44-
EnableCrossPartitionQuery = true
45-
};
43+
var options = new FeedOptions
44+
{
45+
EnableCrossPartitionQuery = true
46+
};
4647

47-
IDocumentQuery<Document> documentQuery = client.CreateDocumentQuery<Document>(collUri, "SELECT * FROM c WHERE STARTSWITH(c.id, @PartitionLeasePrefix)", options).AsDocumentQuery<Document>();
48+
IDocumentQuery<Document> documentQuery = client.CreateDocumentQuery<Document>(collUri, "SELECT * FROM c WHERE STARTSWITH(c.id, @PartitionLeasePrefix)", options).AsDocumentQuery<Document>();
4849

49-
await documentQuery.ExecuteNextAsync();
50+
await documentQuery.ExecuteNextAsync();
51+
}
52+
catch (Exception ex)
53+
{
54+
return new ObjectResult(ex.ToString())
55+
{
56+
StatusCode = 500
57+
};
58+
}
5059

5160
return new OkResult();
5261
}

test/CSharpPrecompiledTestProjects/NativeDependencyOldSdk/NativeDependencyOldSdk.cs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,38 @@ public NativeDependencyOldSdk(IConfiguration config)
2424
public async Task<IActionResult> Run(
2525
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req)
2626
{
27-
// Issue a query against Cosmos that forces a native assembly to load.
28-
29-
string cosmosConnection = _config.GetConnectionString("CosmosDB");
30-
var builder = new DbConnectionStringBuilder()
27+
try
3128
{
32-
ConnectionString = cosmosConnection
33-
};
29+
// Issue a query against Cosmos that forces a native assembly to load.
3430

35-
builder.TryGetValue("AccountEndpoint", out object dbUri);
36-
builder.TryGetValue("AccountKey", out object dbKey);
31+
string cosmosConnection = _config.GetConnectionString("CosmosDB");
32+
var builder = new DbConnectionStringBuilder()
33+
{
34+
ConnectionString = cosmosConnection
35+
};
3736

38-
var client = new DocumentClient(new Uri(dbUri.ToString()), dbKey.ToString());
39-
Uri collUri = UriFactory.CreateDocumentCollectionUri("ItemDb", "ItemCollection");
37+
builder.TryGetValue("AccountEndpoint", out object dbUri);
38+
builder.TryGetValue("AccountKey", out object dbKey);
4039

41-
var options = new FeedOptions
42-
{
43-
EnableCrossPartitionQuery = true
44-
};
40+
var client = new DocumentClient(new Uri(dbUri.ToString()), dbKey.ToString());
41+
Uri collUri = UriFactory.CreateDocumentCollectionUri("ItemDb", "ItemCollection");
4542

46-
IDocumentQuery<Document> documentQuery = client.CreateDocumentQuery<Document>(collUri, "SELECT * FROM c WHERE STARTSWITH(c.id, @PartitionLeasePrefix)", options).AsDocumentQuery<Document>();
43+
var options = new FeedOptions
44+
{
45+
EnableCrossPartitionQuery = true
46+
};
4747

48-
await documentQuery.ExecuteNextAsync();
48+
IDocumentQuery<Document> documentQuery = client.CreateDocumentQuery<Document>(collUri, "SELECT * FROM c WHERE STARTSWITH(c.id, @PartitionLeasePrefix)", options).AsDocumentQuery<Document>();
49+
50+
await documentQuery.ExecuteNextAsync();
51+
}
52+
catch (Exception ex)
53+
{
54+
return new ObjectResult(ex.ToString())
55+
{
56+
StatusCode = 500
57+
};
58+
}
4959

5060
return new OkResult();
5161
}

test/CSharpPrecompiledTestProjects/ReferenceOlderRuntimeAssembly/ReferenceOlderRuntimeAssembly.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using System;
21
using Microsoft.AspNetCore.Http;
32
using Microsoft.AspNetCore.Mvc;
43
using Microsoft.Azure.WebJobs;
@@ -9,7 +8,6 @@ namespace ReferenceOlderRuntimeAssembly
98
{
109
public class ReferenceOlderRuntimeAssembly
1110
{
12-
public static IHostingEnvironment StartupEnv;
1311
private readonly IHostingEnvironment _env;
1412

1513
public ReferenceOlderRuntimeAssembly(IHostingEnvironment env)
@@ -23,7 +21,10 @@ public IActionResult Run(
2321
{
2422
if (_env == null)
2523
{
26-
throw new InvalidOperationException();
24+
return new ObjectResult("IHostingEnvironment was not injected into the function class.")
25+
{
26+
StatusCode = 500
27+
};
2728
}
2829

2930
return new OkResult();

test/CSharpPrecompiledTestProjects/WebJobsStartupTests/Function1.cs

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,27 +28,59 @@ public Function1(IMyService myService, IOptions<MyOptions> myOptions, IConfigura
2828
[FunctionName("Function1")]
2929
public IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req)
3030
{
31-
if (!(_myService is MyService))
31+
try
3232
{
33-
throw new InvalidOperationException();
34-
}
33+
if (!(_myService is MyService))
34+
{
35+
return new ObjectResult("_myService is not of type MyService")
36+
{
37+
StatusCode = 500
38+
};
39+
}
3540

36-
if (_myOptions.MyKey != "MyValue" || _myOptions.MyOtherKey != "FromEnvironment")
37-
{
38-
throw new InvalidOperationException();
39-
}
41+
if (_myOptions.MyKey != "MyValue")
42+
{
43+
return new ObjectResult($"_myOptions.MyKey is {_myOptions.MyKey}")
44+
{
45+
StatusCode = 500
46+
};
47+
}
4048

41-
if (_config["SomeOtherKey"] != "SomeOtherValue")
42-
{
43-
throw new InvalidOperationException();
44-
}
49+
if (_myOptions.MyOtherKey != "FromEnvironment")
50+
{
51+
return new ObjectResult($"_myOptions.MyOtherKey is {_myOptions.MyOtherKey}")
52+
{
53+
StatusCode = 500
54+
};
4555

46-
if (!ValidateConfig(_config))
56+
}
57+
58+
if (_config["SomeOtherKey"] != "SomeOtherValue")
59+
{
60+
return new ObjectResult($"SomeOtherKey is {_config["SomeOtherKey"]}")
61+
{
62+
StatusCode = 500
63+
};
64+
}
65+
66+
if (!ValidateConfig(_config))
67+
{
68+
return new ObjectResult("Configuration validation failed.")
69+
{
70+
StatusCode = 500
71+
};
72+
}
73+
}
74+
catch (Exception ex)
4775
{
48-
throw new InvalidOperationException();
76+
return new ObjectResult(ex.ToString())
77+
{
78+
StatusCode = 500
79+
};
80+
4981
}
5082

51-
return new OkObjectResult("ok");
83+
return new OkResult();
5284
}
5385

5486
// Use this to test overwriting a trigger parameter.

test/WebJobs.Script.Tests.Integration/WebHostEndToEnd/FunctionAssemblyLoadContextEndToEndTests.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ await RunTest(async () =>
3636
var response = await client.GetAsync($"api/Function1");
3737

3838
// The function does all the validation internally.
39-
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
39+
Assert.True(HttpStatusCode.OK == response.StatusCode, $"Test failed with {response.StatusCode}: {await response.Content.ReadAsStringAsync()}");
4040
});
4141
}
4242

@@ -64,7 +64,7 @@ await RunTest(async () =>
6464
var response = await client.GetAsync($"api/NativeDependencyOldSdk");
6565

6666
// The function does all the validation internally.
67-
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
67+
Assert.True(HttpStatusCode.OK == response.StatusCode, $"Test failed with {response.StatusCode}: {await response.Content.ReadAsStringAsync()}");
6868
});
6969
}
7070

@@ -92,7 +92,7 @@ await RunTest(async () =>
9292
var response = await client.GetAsync($"api/NativeDependencyNoRuntimes");
9393

9494
// The function does all the validation internally.
95-
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
95+
Assert.True(HttpStatusCode.OK == response.StatusCode, $"Test failed with {response.StatusCode}: {await response.Content.ReadAsStringAsync()}");
9696
});
9797
}
9898

@@ -110,7 +110,7 @@ await RunTest(async () =>
110110
var response = await client.GetAsync($"api/MultipleDependencyVersions");
111111

112112
// The function does all the validation internally.
113-
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
113+
Assert.True(HttpStatusCode.OK == response.StatusCode, $"Test failed with {response.StatusCode}: {await response.Content.ReadAsStringAsync()}");
114114
});
115115
}
116116

@@ -131,7 +131,7 @@ await RunTest(async () =>
131131
var response = await client.GetAsync($"api/ReferenceOlderRuntimeAssembly");
132132

133133
// The function does all the validation internally.
134-
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
134+
Assert.True(HttpStatusCode.OK == response.StatusCode, $"Test failed with {response.StatusCode}: {await response.Content.ReadAsStringAsync()}");
135135
});
136136
}
137137

@@ -148,7 +148,6 @@ private async Task RunTest(Func<Task> test)
148148
}
149149
}
150150

151-
152151
public void Dispose()
153152
{
154153
_launcher?.Dispose();
@@ -170,4 +169,4 @@ public void Dispose()
170169
}
171170
}
172171
}
173-
}
172+
}

0 commit comments

Comments
 (0)