Skip to content

Conversation

@jonathanpeppers
Copy link
Member

MSBuild tests using DownloadedCache can randomly fail with HTTP errors such as:

System.Net.Http.HttpRequestException : Response status code does not indicate success: 504 (Gateway Time-out).
Stack trace
at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
at Xamarin.ProjectTools.DownloadedCache.GetAsFile(String url, String filename) in /Users/runner/work/1/s/android/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DownloadedCache.cs:line 39
at Xamarin.ProjectTools.BuildItem.<>c__DisplayClass70_0.<set_WebContent>b__0() in /Users/runner/work/1/s/android/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildItem.cs:line 309
at Xamarin.ProjectTools.XamarinProject.<>c.<Save>b__110_0(BuildItem s) in /Users/runner/work/1/s/android/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs:line 455
at System.Collections.Generic.List`1.AddRange(IEnumerable`1 collection)
at Xamarin.ProjectTools.XamarinProject.Save(Boolean saveProject) in /Users/runner/work/1/s/android/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs:line 455
at Xamarin.ProjectTools.ProjectBuilder.Save(XamarinProject project, Boolean doNotCleanupOnUpdate, Boolean saveProject) in /Users/runner/work/1/s/android/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/ProjectBuilder.cs:line 98
at Xamarin.ProjectTools.ProjectBuilder.Build(XamarinProject project, Boolean doNotCleanupOnUpdate, String[] parameters, Boolean saveProject, Dictionary`2 environmentVariables) in /Users/runner/work/1/s/android/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/ProjectBuilder.cs:line 128
at Xamarin.Android.Build.Tests.BindingBuildTest.BindngFilterUnsupportedNativeAbiLibraries(AndroidRuntime runtime) in /Users/runner/work/1/s/android/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs:line 411
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)

Let's call Assert.Inconclusive() when we catch such exceptions, so that the test is marked as inconclusive instead of failed.

We also log information about the exception.

MSBuild tests using `DownloadedCache` can randomly fail with HTTP
errors such as:

    System.Net.Http.HttpRequestException : Response status code does not indicate success: 504 (Gateway Time-out).
    Stack trace
    at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
    at Xamarin.ProjectTools.DownloadedCache.GetAsFile(String url, String filename) in /Users/runner/work/1/s/android/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DownloadedCache.cs:line 39
    at Xamarin.ProjectTools.BuildItem.<>c__DisplayClass70_0.<set_WebContent>b__0() in /Users/runner/work/1/s/android/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildItem.cs:line 309
    at Xamarin.ProjectTools.XamarinProject.<>c.<Save>b__110_0(BuildItem s) in /Users/runner/work/1/s/android/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs:line 455
    at System.Collections.Generic.List`1.AddRange(IEnumerable`1 collection)
    at Xamarin.ProjectTools.XamarinProject.Save(Boolean saveProject) in /Users/runner/work/1/s/android/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs:line 455
    at Xamarin.ProjectTools.ProjectBuilder.Save(XamarinProject project, Boolean doNotCleanupOnUpdate, Boolean saveProject) in /Users/runner/work/1/s/android/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/ProjectBuilder.cs:line 98
    at Xamarin.ProjectTools.ProjectBuilder.Build(XamarinProject project, Boolean doNotCleanupOnUpdate, String[] parameters, Boolean saveProject, Dictionary`2 environmentVariables) in /Users/runner/work/1/s/android/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/ProjectBuilder.cs:line 128
    at Xamarin.Android.Build.Tests.BindingBuildTest.BindngFilterUnsupportedNativeAbiLibraries(AndroidRuntime runtime) in /Users/runner/work/1/s/android/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs:line 411
    at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
    at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)

Let's call `Assert.Inconclusive()` when we catch such exceptions,
so that the test is marked as inconclusive instead of failed.

We also log information about the exception.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves test reliability by handling transient HTTP errors gracefully. When tests download resources using DownloadedCache, transient network failures (timeouts, gateway errors, etc.) will now mark tests as inconclusive rather than failed, with detailed logging to aid debugging.

Key changes:

  • Added try-catch block to handle HttpRequestException with transient error filtering
  • Implemented IsTransientError() method to identify recoverable HTTP errors (504, 408, 502, 503)
  • Added comprehensive logging before marking tests inconclusive

Comment on lines +64 to +68
// Check for timeout errors
if (ex.Message.Contains ("504") || ex.Message.Contains ("Gateway Time-out"))
return true;

// Check for other common transient errors
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The message-based check for "504" and "Gateway Time-out" is fragile and redundant. Line 72 already handles HttpStatusCode.GatewayTimeout (which is 504), making this string check unnecessary. String matching on exception messages is brittle since message formats can vary across different .NET versions or localization settings. Remove these lines and rely solely on the StatusCode property check.

Suggested change
// Check for timeout errors
if (ex.Message.Contains ("504") || ex.Message.Contains ("Gateway Time-out"))
return true;
// Check for other common transient errors
// Check for common transient HTTP status codes

Copilot uses AI. Check for mistakes.
// Check for timeout errors
if (ex.Message.Contains ("504") || ex.Message.Contains ("Gateway Time-out"))
return true;

Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the trailing whitespace on this empty line to maintain code consistency.

Suggested change

Copilot uses AI. Check for mistakes.
statusCode == HttpStatusCode.ServiceUnavailable ||
statusCode == HttpStatusCode.BadGateway;
}

Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the trailing whitespace on this empty line to maintain code consistency.

Copilot uses AI. Check for mistakes.
Comment on lines +71 to +74
return statusCode == HttpStatusCode.RequestTimeout ||
statusCode == HttpStatusCode.GatewayTimeout ||
statusCode == HttpStatusCode.ServiceUnavailable ||
statusCode == HttpStatusCode.BadGateway;
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The multi-line return statement should follow the project's formatting style. Based on the coding guidelines, this should be formatted with each condition on its own line with proper indentation, or use a more compact style with parentheses. The current formatting with the continuation is inconsistent with typical Mono style.

Suggested change
return statusCode == HttpStatusCode.RequestTimeout ||
statusCode == HttpStatusCode.GatewayTimeout ||
statusCode == HttpStatusCode.ServiceUnavailable ||
statusCode == HttpStatusCode.BadGateway;
return statusCode == HttpStatusCode.RequestTimeout
|| statusCode == HttpStatusCode.GatewayTimeout
|| statusCode == HttpStatusCode.ServiceUnavailable
|| statusCode == HttpStatusCode.BadGateway;

Copilot uses AI. Check for mistakes.
}
}
} catch (HttpRequestException ex) when (IsTransientError (ex)) {
TestContext.WriteLine ($"Transient network error downloading '{url}':");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, this actually needs to File.Delete(filename)...

Probably also need a try-catch-throw that does the same thing for all uncaught exceptions.

@jonathanpeppers jonathanpeppers marked this pull request as draft December 18, 2025 22:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants