Skip to content

Commit 784e7c7

Browse files
authored
trace2: add error event (#1156)
This series adds the `TRACE2` error event. The first two commits are opportunistic fixes that remove unnecessary components of `Trace2` messages. The next four commits add `Trace2` as a dependency to certain classes where exceptions are thrown in order to capture those exceptions with the new error event. The seventh commit adds the error event, and eighth adds special exceptions that write to `Trace2`. Finally, the ninth commit adds error tracing exceptions and messages throughout the GCM codebase.
2 parents 65e5a88 + 94f8d91 commit 784e7c7

File tree

56 files changed

+603
-305
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+603
-305
lines changed

src/shared/Atlassian.Bitbucket.Tests/Cloud/BitbucketOAuth2ClientTest.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Atlassian.Bitbucket.Cloud;
88
using GitCredentialManager;
99
using GitCredentialManager.Authentication.OAuth;
10+
using GitCredentialManager.Tests.Objects;
1011
using Moq;
1112
using Xunit;
1213

@@ -16,7 +17,6 @@ public class BitbucketOAuth2ClientTest
1617
{
1718
private Mock<HttpClient> httpClient = new Mock<HttpClient>(MockBehavior.Strict);
1819
private Mock<ISettings> settings = new Mock<ISettings>(MockBehavior.Loose);
19-
private Mock<Trace> trace = new Mock<Trace>(MockBehavior.Loose);
2020
private Mock<IOAuth2WebBrowser> browser = new Mock<IOAuth2WebBrowser>(MockBehavior.Strict);
2121
private Mock<IOAuth2CodeGenerator> codeGenerator = new Mock<IOAuth2CodeGenerator>(MockBehavior.Strict);
2222
private IEnumerable<string> scopes = new List<string>();
@@ -55,7 +55,7 @@ public async Task BitbucketOAuth2Client_GetAuthorizationCodeAsync_RespectsClient
5555
Uri finalCallbackUri = MockFinalCallbackUri();
5656

5757
Bitbucket.Cloud.BitbucketOAuth2Client client = GetBitbucketOAuth2Client();
58-
58+
5959
MockGetAuthenticationCodeAsync(finalCallbackUri, clientId, client.Scopes);
6060

6161
MockCodeGenerator();
@@ -68,8 +68,9 @@ public async Task BitbucketOAuth2Client_GetAuthorizationCodeAsync_RespectsClient
6868
[Fact]
6969
public async Task BitbucketOAuth2Client_GetDeviceCodeAsync()
7070
{
71-
var client = new Bitbucket.Cloud.BitbucketOAuth2Client(httpClient.Object, settings.Object, trace.Object);
72-
await Assert.ThrowsAsync<InvalidOperationException>(async () => await client.GetDeviceCodeAsync(scopes, ct));
71+
var trace2 = new NullTrace2();
72+
var client = new Bitbucket.Cloud.BitbucketOAuth2Client(httpClient.Object, settings.Object, trace2);
73+
await Assert.ThrowsAsync<Trace2InvalidOperationException>(async () => await client.GetDeviceCodeAsync(scopes, ct));
7374
}
7475

7576
[Theory]
@@ -79,7 +80,8 @@ public async Task BitbucketOAuth2Client_GetDeviceCodeAsync()
7980
[InlineData("https", "example.com/", "john", "https://example.com/refresh_token")]
8081
public void BitbucketOAuth2Client_GetRefreshTokenServiceName(string protocol, string host, string username, string expectedResult)
8182
{
82-
var client = new Bitbucket.Cloud.BitbucketOAuth2Client(httpClient.Object, settings.Object, trace.Object);
83+
var trace2 = new NullTrace2();
84+
var client = new Bitbucket.Cloud.BitbucketOAuth2Client(httpClient.Object, settings.Object, trace2);
8385
var input = new InputArguments(new Dictionary<string, string>
8486
{
8587
["protocol"] = protocol,
@@ -100,7 +102,8 @@ private void VerifyAuthorizationCodeResult(OAuth2AuthorizationCodeResult result)
100102

101103
private Bitbucket.Cloud.BitbucketOAuth2Client GetBitbucketOAuth2Client()
102104
{
103-
var client = new Bitbucket.Cloud.BitbucketOAuth2Client(httpClient.Object, settings.Object, trace.Object);
105+
var trace2 = new NullTrace2();
106+
var client = new Bitbucket.Cloud.BitbucketOAuth2Client(httpClient.Object, settings.Object, trace2);
104107
client.CodeGenerator = codeGenerator.Object;
105108
return client;
106109
}

src/shared/Atlassian.Bitbucket.Tests/DataCenter/BitbucketOAuth2ClientTest.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Atlassian.Bitbucket.DataCenter;
88
using GitCredentialManager;
99
using GitCredentialManager.Authentication.OAuth;
10+
using GitCredentialManager.Tests.Objects;
1011
using Moq;
1112
using Xunit;
1213

@@ -16,7 +17,6 @@ public class BitbucketOAuth2ClientTest
1617
{
1718
private Mock<HttpClient> httpClient = new Mock<HttpClient>(MockBehavior.Strict);
1819
private Mock<ISettings> settings = new Mock<ISettings>(MockBehavior.Loose);
19-
private Mock<Trace> trace = new Mock<Trace>(MockBehavior.Loose);
2020
private Mock<IOAuth2WebBrowser> browser = new Mock<IOAuth2WebBrowser>(MockBehavior.Strict);
2121
private Mock<IOAuth2CodeGenerator> codeGenerator = new Mock<IOAuth2CodeGenerator>(MockBehavior.Strict);
2222
private CancellationToken ct = new CancellationToken();
@@ -77,7 +77,8 @@ private void VerifyAuthorizationCodeResult(OAuth2AuthorizationCodeResult result,
7777

7878
private Bitbucket.DataCenter.BitbucketOAuth2Client GetBitbucketOAuth2Client()
7979
{
80-
var client = new Bitbucket.DataCenter.BitbucketOAuth2Client(httpClient.Object, settings.Object, trace.Object);
80+
var trace2 = new NullTrace2();
81+
var client = new Bitbucket.DataCenter.BitbucketOAuth2Client(httpClient.Object, settings.Object, trace2);
8182
client.CodeGenerator = codeGenerator.Object;
8283
return client;
8384
}

src/shared/Atlassian.Bitbucket.UI/Commands/CredentialsCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ private async Task<int> ExecuteAsync(Uri url, string userName, bool showOAuth, b
4848

4949
if (!viewModel.WindowResult || viewModel.SelectedMode == AuthenticationModes.None)
5050
{
51-
throw new Exception("User cancelled dialog.");
51+
throw new Trace2Exception(Context.Trace2, "User cancelled dialog.");
5252
}
5353

5454
switch (viewModel.SelectedMode)

src/shared/Atlassian.Bitbucket/BitbucketAuthentication.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System.Text;
55
using System.Threading;
66
using System.Threading.Tasks;
7-
using Atlassian.Bitbucket.Cloud;
87
using GitCredentialManager;
98
using GitCredentialManager.Authentication;
109
using GitCredentialManager.Authentication.OAuth;
@@ -128,12 +127,12 @@ public async Task<CredentialsPromptResult> GetCredentialsAsync(Uri targetUri, st
128127
{
129128
if (!output.TryGetValue("username", out userName))
130129
{
131-
throw new Exception("Missing username in response");
130+
throw new Trace2Exception(Context.Trace2, "Missing username in response");
132131
}
133132

134133
if (!output.TryGetValue("password", out password))
135134
{
136-
throw new Exception("Missing password in response");
135+
throw new Trace2Exception(Context.Trace2, "Missing password in response");
137136
}
138137

139138
return new CredentialsPromptResult(

src/shared/Atlassian.Bitbucket/BitbucketHostProvider.cs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Net;
43
using System.Net.Http;
54
using System.Threading.Tasks;
65
using Atlassian.Bitbucket.Cloud;
@@ -79,7 +78,8 @@ public async Task<ICredential> GetCredentialAsync(InputArguments input)
7978
if (StringComparer.OrdinalIgnoreCase.Equals(input.Protocol, "http")
8079
&& BitbucketHelper.IsBitbucketOrg(input))
8180
{
82-
throw new Exception("Unencrypted HTTP is not supported for Bitbucket.org. Ensure the repository remote URL is using HTTPS.");
81+
throw new Trace2Exception(_context.Trace2,
82+
"Unencrypted HTTP is not supported for Bitbucket.org. Ensure the repository remote URL is using HTTPS.");
8383
}
8484

8585
var authModes = await GetSupportedAuthenticationModesAsync(input);
@@ -145,8 +145,9 @@ private async Task<ICredential> GetRefreshedCredentials(InputArguments input, Au
145145
var result = await _bitbucketAuth.GetCredentialsAsync(remoteUri, input.UserName, authModes);
146146
if (result is null || result.AuthenticationMode == AuthenticationModes.None)
147147
{
148-
_context.Trace.WriteLine("User cancelled credential prompt");
149-
throw new Exception("User cancelled credential prompt.");
148+
var message = "User cancelled credential prompt";
149+
_context.Trace.WriteLine(message);
150+
throw new Trace2Exception(_context.Trace2, message);
150151
}
151152

152153
switch (result.AuthenticationMode)
@@ -176,8 +177,10 @@ private async Task<ICredential> GetRefreshedCredentials(InputArguments input, Au
176177
}
177178
catch (OAuth2Exception ex)
178179
{
179-
_context.Trace.WriteLine("Failed to refresh existing OAuth credential using refresh token");
180+
var message = "Failed to refresh existing OAuth credential using refresh token";
181+
_context.Trace.WriteLine(message);
180182
_context.Trace.WriteException(ex);
183+
_context.Trace2.WriteError(message);
181184

182185
// We failed to refresh the AT using the RT; log the refresh failure and fall through to restart
183186
// the OAuth authentication flow
@@ -279,7 +282,7 @@ public async Task<AuthenticationModes> GetSupportedAuthenticationModesAsync(Inpu
279282
try
280283
{
281284
var authenticationMethods = await _restApiRegistry.Get(input).GetAuthenticationMethodsAsync();
282-
285+
283286
var modes = AuthenticationModes.None;
284287

285288
if (authenticationMethods.Contains(AuthenticationMethod.BasicAuth))
@@ -298,10 +301,14 @@ public async Task<AuthenticationModes> GetSupportedAuthenticationModesAsync(Inpu
298301
}
299302
catch (Exception ex)
300303
{
301-
_context.Trace.WriteLine($"Failed to query '{input.GetRemoteUri()}' for supported authentication schemes.");
304+
var format = "Failed to query '{0}' for supported authentication schemes.";
305+
var message = string.Format(format, input.GetRemoteUri());
306+
307+
_context.Trace.WriteLine(message);
302308
_context.Trace.WriteException(ex);
309+
_context.Trace2.WriteError(message, format);
303310

304-
_context.Terminal.WriteLine($"warning: failed to query '{input.GetRemoteUri()}' for supported authentication schemes.");
311+
_context.Terminal.WriteLine($"warning: {message}");
305312

306313
// Fall-back to offering all modes so the user is never blocked from authenticating by at least one mode
307314
return AuthenticationModes.All;
@@ -356,7 +363,8 @@ private async Task<string> ResolveOAuthUserNameAsync(InputArguments input, strin
356363
return result.Response.UserName;
357364
}
358365

359-
throw new Exception($"Failed to resolve username. HTTP: {result.StatusCode}");
366+
throw new Trace2Exception(_context.Trace2,
367+
$"Failed to resolve username. HTTP: {result.StatusCode}");
360368
}
361369

362370
private async Task<string> ResolveBasicAuthUserNameAsync(InputArguments input, string username, string password)
@@ -367,7 +375,8 @@ private async Task<string> ResolveBasicAuthUserNameAsync(InputArguments input, s
367375
return result.Response.UserName;
368376
}
369377

370-
throw new Exception($"Failed to resolve username. HTTP: {result.StatusCode}");
378+
throw new Trace2Exception(_context.Trace2,
379+
$"Failed to resolve username. HTTP: {result.StatusCode}");
371380
}
372381

373382
private async Task<bool> ValidateCredentialsWork(InputArguments input, ICredential credentials, AuthenticationModes authModes)
@@ -404,8 +413,10 @@ private async Task<bool> ValidateCredentialsWork(InputArguments input, ICredenti
404413
}
405414
catch (Exception ex)
406415
{
407-
_context.Trace.WriteLine($"Failed to validate existing credentials using OAuth");
416+
var message = "Failed to validate existing credentials using OAuth";
417+
_context.Trace.WriteLine(message);
408418
_context.Trace.WriteException(ex);
419+
_context.Trace2.WriteError(message);
409420
}
410421
}
411422

@@ -419,8 +430,10 @@ private async Task<bool> ValidateCredentialsWork(InputArguments input, ICredenti
419430
}
420431
catch (Exception ex)
421432
{
422-
_context.Trace.WriteLine($"Failed to validate existing credentials using Basic Auth");
433+
var message = "Failed to validate existing credentials using Basic Auth";
434+
_context.Trace.WriteLine(message);
423435
_context.Trace.WriteException(ex);
436+
_context.Trace2.WriteError(message);
424437
return false;
425438
}
426439
}

src/shared/Atlassian.Bitbucket/BitbucketOAuth2Client.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ namespace Atlassian.Bitbucket
1010
{
1111
public abstract class BitbucketOAuth2Client : OAuth2Client
1212
{
13-
public BitbucketOAuth2Client(HttpClient httpClient, OAuth2ServerEndpoints endpoints, string clientId, Uri redirectUri, string clientSecret, ITrace trace) : base(httpClient, endpoints, clientId, redirectUri, clientSecret, false)
13+
public BitbucketOAuth2Client(HttpClient httpClient,
14+
OAuth2ServerEndpoints endpoints,
15+
string clientId,
16+
Uri redirectUri,
17+
string clientSecret,
18+
ITrace2 trace2) : base(httpClient, endpoints, clientId, trace2, redirectUri, clientSecret, false)
1419
{
1520
}
1621

src/shared/Atlassian.Bitbucket/Cloud/BitbucketOAuth2Client.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ namespace Atlassian.Bitbucket.Cloud
1010
{
1111
public class BitbucketOAuth2Client : Bitbucket.BitbucketOAuth2Client
1212
{
13-
public BitbucketOAuth2Client(HttpClient httpClient, ISettings settings, ITrace trace)
13+
public BitbucketOAuth2Client(HttpClient httpClient, ISettings settings, ITrace2 trace2)
1414
: base(httpClient, GetEndpoints(),
15-
GetClientId(settings), GetRedirectUri(settings), GetClientSecret(settings), trace)
15+
GetClientId(settings), GetRedirectUri(settings), GetClientSecret(settings), trace2)
1616
{
1717
}
1818

@@ -62,7 +62,7 @@ private static string GetClientSecret(ISettings settings)
6262

6363
return CloudConstants.OAuth2ClientSecret;
6464
}
65-
65+
6666
private static OAuth2ServerEndpoints GetEndpoints()
6767
{
6868
return new OAuth2ServerEndpoints(

src/shared/Atlassian.Bitbucket/DataCenter/BitbucketOAuth2Client.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ namespace Atlassian.Bitbucket.DataCenter
1212
{
1313
public class BitbucketOAuth2Client : Bitbucket.BitbucketOAuth2Client
1414
{
15-
public BitbucketOAuth2Client(HttpClient httpClient, ISettings settings, ITrace trace)
15+
public BitbucketOAuth2Client(HttpClient httpClient, ISettings settings, ITrace2 trace2)
1616
: base(httpClient, GetEndpoints(settings),
17-
GetClientId(settings), GetRedirectUri(settings), GetClientSecret(settings), trace)
17+
GetClientId(settings), GetRedirectUri(settings), GetClientSecret(settings), trace2)
1818
{
1919
}
2020

src/shared/Atlassian.Bitbucket/DataCenter/BitbucketRestApi.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public BitbucketRestApi(ICommandContext context)
2020
EnsureArgument.NotNull(context, nameof(context));
2121

2222
_context = context;
23-
23+
2424
}
2525

2626
public async Task<RestApiResult<IUserInfo>> GetUserInformationAsync(string userName, string password, bool isBearerToken)
@@ -35,7 +35,7 @@ public async Task<RestApiResult<IUserInfo>> GetUserInformationAsync(string userN
3535
}
3636

3737
// Bitbucket Server/DC doesn't actually provide a REST API we can use to trade an access_token for the owning username,
38-
// therefore this is always going to return a placeholder username, however this call does provide a way to validate the
38+
// therefore this is always going to return a placeholder username, however this call does provide a way to validate the
3939
// credentials we do have
4040
var requestUri = new Uri(ApiUri, "api/1.0/users");
4141
using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUri))
@@ -131,9 +131,9 @@ public void Dispose()
131131

132132
private HttpClient HttpClient => _httpClient ??= _context.HttpClientFactory.CreateClient();
133133

134-
private Uri ApiUri
134+
private Uri ApiUri
135135
{
136-
get
136+
get
137137
{
138138
var remoteUri = _context.Settings?.RemoteUri;
139139
if (remoteUri == null)

src/shared/Atlassian.Bitbucket/OAuth2ClientRegistry.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public class OAuth2ClientRegistry : IRegistry<BitbucketOAuth2Client>
88
private readonly HttpClient http;
99
private ISettings settings;
1010
private readonly ITrace trace;
11+
private readonly ITrace2 trace2;
1112
private Cloud.BitbucketOAuth2Client cloudClient;
1213
private DataCenter.BitbucketOAuth2Client dataCenterClient;
1314

@@ -16,6 +17,7 @@ public OAuth2ClientRegistry(ICommandContext context)
1617
this.http = context.HttpClientFactory.CreateClient();
1718
this.settings = context.Settings;
1819
this.trace = context.Trace;
20+
this.trace2 = context.Trace2;
1921
}
2022

2123
public BitbucketOAuth2Client Get(InputArguments input)
@@ -36,7 +38,7 @@ public void Dispose()
3638
dataCenterClient = null;
3739
}
3840

39-
private Cloud.BitbucketOAuth2Client CloudClient => cloudClient ??= new Cloud.BitbucketOAuth2Client(http, settings, trace);
40-
private DataCenter.BitbucketOAuth2Client DataCenterClient => dataCenterClient ??= new DataCenter.BitbucketOAuth2Client(http, settings, trace);
41+
private Cloud.BitbucketOAuth2Client CloudClient => cloudClient ??= new Cloud.BitbucketOAuth2Client(http, settings, trace2);
42+
private DataCenter.BitbucketOAuth2Client DataCenterClient => dataCenterClient ??= new DataCenter.BitbucketOAuth2Client(http, settings, trace2);
4143
}
42-
}
44+
}

src/shared/Core.Tests/Authentication/MicrosoftAuthenticationTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public async System.Threading.Tasks.Task MicrosoftAuthentication_GetAccessTokenA
2323

2424
var msAuth = new MicrosoftAuthentication(context);
2525

26-
await Assert.ThrowsAsync<InvalidOperationException>(
26+
await Assert.ThrowsAsync<Trace2InvalidOperationException>(
2727
() => msAuth.GetTokenAsync(authority, clientId, redirectUri, scopes, userName));
2828
}
2929
}

0 commit comments

Comments
 (0)