Skip to content

Commit

Permalink
diagnose: add http fallback uri
Browse files Browse the repository at this point in the history
Currently, failure to access http://example.com causes failure of the
Networking Diagnostic portion of the diagnose command. To improve the
experience for users who are unable to access http://example.com, this
change:

1. Adds a fallback URI - if accessing http://example.com throws an
exception, we now try http://httpforever.com.
2. Prints a warning when either the primary or both the primary and
fallback uris throw an exception (instead of failing the Networking
Diagnostic).
  • Loading branch information
ldennington committed Jul 17, 2023
1 parent 0d70623 commit 303996a
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 3 deletions.
44 changes: 44 additions & 0 deletions src/shared/Core.Tests/Commands/DiagnoseCommandTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System;
using System.Net.Http;
using System.Text;
using GitCredentialManager.Diagnostics;
using GitCredentialManager.Tests.Objects;
using Xunit;

namespace Core.Tests.Commands;

public class DiagnoseCommandTests
{
[Theory]
[InlineData(false, false, 0, "Sending HEAD request to http://example.com... OK\n")]
[InlineData(true, false, 1, "Sending HEAD request to http://example.com... warning: HEAD request failed.\n" +
"Sending HEAD request to http://httpforever.com... OK\n")]
[InlineData(false, true, 1, "Sending HEAD request to http://example.com... warning: HEAD request failed.\n" +
"Sending HEAD request to http://httpforever.com... warning: HEAD request failed.\n")]
public void NetworkingDiagnostic_SendHttpRequest(bool simulatePrimaryUriFailure, bool simulateNoNetwork,
int expectedBackupCalls, string expectedOutput)
{
var primaryUriString = "http://example.com";
var backupUriString = "http://httpforever.com";
var sb = new StringBuilder();
var context = new TestCommandContext();
var networkingDiagnostic = new NetworkingDiagnostic(context);
var primaryUri = new Uri(primaryUriString);
var backupUri = new Uri(backupUriString);
var httpHandler = new TestHttpMessageHandler
{
SimulatePrimaryUriFailure = simulatePrimaryUriFailure,
SimulateNoNetwork = simulateNoNetwork
};
var httpResponse = new HttpResponseMessage();

httpHandler.Setup(HttpMethod.Head, primaryUri, httpResponse);
httpHandler.Setup(HttpMethod.Head, backupUri, httpResponse);

networkingDiagnostic.SendHttpRequest(sb, new HttpClient(httpHandler));

httpHandler.AssertRequest(HttpMethod.Head, primaryUri, expectedNumberOfCalls: 1);
httpHandler.AssertRequest(HttpMethod.Head, backupUri, expectedNumberOfCalls: expectedBackupCalls);
Assert.Equal(expectedOutput, sb.ToString());
}
}
23 changes: 20 additions & 3 deletions src/shared/Core/Diagnostics/NetworkingDiagnostic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace GitCredentialManager.Diagnostics
public class NetworkingDiagnostic : Diagnostic
{
private const string TestHttpUri = "http://example.com";
private const string TestHttpUriFallback = "http://httpforever.com";
private const string TestHttpsUri = "https://example.com";

public NetworkingDiagnostic(ICommandContext commandContext)
Expand All @@ -28,9 +29,7 @@ protected override async Task<bool> RunInternalAsync(StringBuilder log, IList<st
bool hasNetwork = NetworkInterface.GetIsNetworkAvailable();
log.AppendLine($"IsNetworkAvailable: {hasNetwork}");

log.Append($"Sending HEAD request to {TestHttpUri}...");
using var httpResponse = await httpClient.HeadAsync(TestHttpUri);
log.AppendLine(" OK");
SendHttpRequest(log, httpClient);

log.Append($"Sending HEAD request to {TestHttpsUri}...");
using var httpsResponse = await httpClient.HeadAsync(TestHttpsUri);
Expand Down Expand Up @@ -98,5 +97,23 @@ protected override async Task<bool> RunInternalAsync(StringBuilder log, IList<st

return true;
}

internal /* For testing purposes */ async void SendHttpRequest(StringBuilder log, HttpClient httpClient)
{
foreach (var uri in new List<string> { TestHttpUri, TestHttpUriFallback })
{
try
{
log.Append($"Sending HEAD request to {uri}...");
using var httpResponse = await httpClient.HeadAsync(uri);
log.AppendLine(" OK");
break;
}
catch (HttpRequestException)
{
log.AppendLine(" warning: HEAD request failed.");
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public class TestHttpMessageHandler : HttpMessageHandler
public bool ThrowOnUnexpectedRequest { get; set; }
public bool SimulateNoNetwork { get; set; }

public bool SimulatePrimaryUriFailure { get; set; }

public IDictionary<(HttpMethod method, Uri uri), int> RequestCounts => _requestCounts;

public void Setup(HttpMethod method, Uri uri, AsyncRequestHandler handler)
Expand Down Expand Up @@ -80,6 +82,12 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
throw new HttpRequestException("Simulated no network");
}

if (SimulatePrimaryUriFailure && request.RequestUri != null &&
request.RequestUri.ToString().Equals("http://example.com/"))
{
throw new HttpRequestException("Simulated http failure.");
}

foreach (var kvp in _handlers)
{
if (kvp.Key == requestKey)
Expand Down

0 comments on commit 303996a

Please sign in to comment.