public void TwoThreadsInterleavingFailuresStillRetriesOnce() { MockTracer tracer = new MockTracer(); MockGitProcess gitProcess = this.GetGitProcess(); GitAuthentication dut = new GitAuthentication(gitProcess, "mock://repoUrl"); dut.TryInitializeAndRequireAuth(tracer, out _); string thread1Auth; string thread1AuthRetry; string thread2Auth; string thread2AuthRetry; string error; // Populate an initial PAT on two threads dut.TryGetCredentials(tracer, out thread1Auth, out error).ShouldEqual(true); dut.TryGetCredentials(tracer, out thread2Auth, out error).ShouldEqual(true); // Simulate a 401 error on one threads dut.RejectCredentials(tracer, thread1Auth); gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(1); gitProcess.CredentialRejections["mock://repoUrl"][0].BasicAuthString.ShouldEqual(thread1Auth); // That thread then retries dut.TryGetCredentials(tracer, out thread1AuthRetry, out error).ShouldEqual(true); // The second thread fails with the old PAT dut.RejectCredentials(tracer, thread2Auth); gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(1, "Should not have rejected a second time"); gitProcess.CredentialRejections["mock://repoUrl"][0].BasicAuthString.ShouldEqual(thread1Auth, "Should only have rejected thread1's initial credential"); // The second thread should be able to get a PAT dut.TryGetCredentials(tracer, out thread2AuthRetry, out error).ShouldEqual(true, error); }
public void AuthShouldBackoffAfterFirstRetryFailure() { MockTracer tracer = new MockTracer(); MockGitProcess gitProcess = this.GetGitProcess(); GitAuthentication dut = new GitAuthentication(gitProcess, "mock://repoUrl"); dut.TryInitializeAndRequireAuth(tracer, out _); string authString; string error; dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to get initial credential"); dut.RejectCredentials(tracer, authString); dut.IsBackingOff.ShouldEqual(false, "Should not backoff after credentials initially rejected"); gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(1); dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to retry getting credential on iteration"); dut.IsBackingOff.ShouldEqual(false, "Should not backoff after successfully getting credentials"); dut.RejectCredentials(tracer, authString); dut.IsBackingOff.ShouldEqual(true, "Should continue to backoff after rejecting credentials"); dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(false, "TryGetCredential should not succeed during backoff"); gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(2); }
public void TwoThreadsFailAtOnceStillRetriesOnce() { MockTracer tracer = new MockTracer(); MockGitProcess gitProcess = this.GetGitProcess(); GitAuthentication dut = new GitAuthentication(gitProcess, "mock://repoUrl"); dut.TryInitializeAndRequireAuth(tracer, out _); string authString; string error; // Populate an initial PAT on two threads dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true); dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true); // Simulate a 401 error on two threads dut.RejectCredentials(tracer, authString); dut.RejectCredentials(tracer, authString); gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(1); gitProcess.CredentialRejections["mock://repoUrl"][0].BasicAuthString.ShouldEqual(authString); // Both threads should still be able to get a PAT for retry purposes dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "The second thread caused back off when it shouldn't"); dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true); }
public void ContinuesToBackoffIfTryGetCredentialsFails() { MockTracer tracer = new MockTracer(); MockGitProcess gitProcess = this.GetGitProcess(); GitAuthentication dut = new GitAuthentication(gitProcess, "mock://repoUrl"); dut.TryInitializeAndRequireAuth(tracer, out _); string authString; string error; dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to get initial credential"); dut.RejectCredentials(tracer, authString); gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(1); gitProcess.ShouldFail = true; dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(false, "Succeeded despite GitProcess returning failure"); dut.IsBackingOff.ShouldEqual(true, "Should continue to backoff if failed to get credentials"); dut.RejectCredentials(tracer, authString); dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(false, "TryGetCredential should not succeed during backoff"); dut.IsBackingOff.ShouldEqual(true, "Should continue to backoff if failed to get credentials"); gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(1); }
public void TwoThreadsInterleavingFailuresStillRetriesOnce() { MockTracer tracer = new MockTracer(); MockEnlistment enlistment = new MockEnlistment(); MockGitProcess gitProcess = new MockGitProcess(enlistment); GitAuthentication dut = new GitAuthentication(gitProcess); string thread1Auth; string thread2Auth; string error; // Populate an initial PAT on two threads dut.TryGetCredentials(tracer, out thread1Auth, out error).ShouldEqual(true); dut.TryGetCredentials(tracer, out thread2Auth, out error).ShouldEqual(true); // Simulate a 401 error on one threads dut.RevokeAndCheckCanRetry(thread1Auth).ShouldEqual(true); // That thread then retries dut.TryGetCredentials(tracer, out thread1Auth, out error).ShouldEqual(true); // The second thread fails with the old PAT dut.RevokeAndCheckCanRetry(thread2Auth).ShouldEqual(true); // The second thread should be able to get a PAT dut.TryGetCredentials(tracer, out thread2Auth, out error).ShouldEqual(true); }
protected ScalarEnlistment CreateEnlistment(string enlistmentRootPath, GitAuthentication authentication) { string gitBinPath = ScalarPlatform.Instance.GitInstallation.GetInstalledGitBinPath(); if (string.IsNullOrWhiteSpace(gitBinPath)) { this.ReportErrorAndExit("Error: " + ScalarConstants.GitIsNotInstalledError); } ScalarEnlistment enlistment = null; try { enlistment = ScalarEnlistment.CreateFromDirectory( enlistmentRootPath, gitBinPath, authentication, createWithoutRepoURL: !this.validateOriginURL); } catch (InvalidRepoException e) { this.ReportErrorAndExit( "Error: '{0}' is not a valid Scalar enlistment. {1}", enlistmentRootPath, e.Message); } return(enlistment); }
public void TwoThreadsInterleavingFailuresShouldntStompASuccess() { MockTracer tracer = new MockTracer(); MockGitProcess gitProcess = this.GetGitProcess(); GitAuthentication dut = new GitAuthentication(gitProcess, "mock://repoUrl"); dut.TryInitializeAndRequireAuth(tracer, out _); string thread1Auth; string thread2Auth; string error; // Populate an initial PAT on two threads dut.TryGetCredentials(tracer, out thread1Auth, out error).ShouldEqual(true); dut.TryGetCredentials(tracer, out thread2Auth, out error).ShouldEqual(true); // Simulate a 401 error on one threads dut.Revoke(thread1Auth); // That thread then retries and succeeds dut.TryGetCredentials(tracer, out thread1Auth, out error).ShouldEqual(true); dut.ConfirmCredentialsWorked(thread1Auth); // If the second thread fails with the old PAT, it shouldn't stomp the new PAT dut.Revoke(thread2Auth); // The second thread should be able to get a PAT dut.TryGetCredentials(tracer, out thread2Auth, out error).ShouldEqual(true); thread2Auth.ShouldEqual(thread1Auth, "The second thread stomp the first threads good auth string"); }
public static GVFSEnlistment CreateFromDirectory( string directory, string gitBinRoot, string gvfsHooksRoot, GitAuthentication authentication, bool createWithoutRepoURL = false) { if (Directory.Exists(directory)) { string errorMessage; string enlistmentRoot; if (!GVFSPlatform.Instance.TryGetGVFSEnlistmentRoot(directory, out enlistmentRoot, out errorMessage)) { throw new InvalidRepoException($"Could not get enlistment root. Error: {errorMessage}"); } if (createWithoutRepoURL) { return(new GVFSEnlistment(enlistmentRoot, string.Empty, gitBinRoot, gvfsHooksRoot, authentication)); } return(new GVFSEnlistment(enlistmentRoot, gitBinRoot, gvfsHooksRoot, authentication)); } throw new InvalidRepoException($"Directory '{directory}' does not exist"); }
public void TwoThreadsInterleavingFailuresStillRetriesOnce() { MockTracer tracer = new MockTracer(); MockGitProcess gitProcess = this.GetGitProcess(); GitAuthentication dut = new GitAuthentication(gitProcess, "mock://repoUrl"); dut.TryInitializeAndRequireAuth(tracer, out _); string thread1Auth; string thread2Auth; string error; // Populate an initial PAT on two threads dut.TryGetCredentials(tracer, out thread1Auth, out error).ShouldEqual(true); dut.TryGetCredentials(tracer, out thread2Auth, out error).ShouldEqual(true); // Simulate a 401 error on one threads dut.Revoke(thread1Auth); // That thread then retries dut.TryGetCredentials(tracer, out thread1Auth, out error).ShouldEqual(true); // The second thread fails with the old PAT dut.Revoke(thread2Auth); // The second thread should be able to get a PAT dut.TryGetCredentials(tracer, out thread2Auth, out error).ShouldEqual(true, error); }
public static ScalarEnlistment CreateFromDirectory( string directory, string gitBinRoot, GitAuthentication authentication, bool createWithoutRepoURL = false) { if (Directory.Exists(directory)) { string enlistmentRoot; string workingDirectory; if (!TryGetScalarEnlistmentRoot(directory, out enlistmentRoot, out workingDirectory)) { throw new InvalidRepoException(directory, $"Could not get enlistment root."); } if (createWithoutRepoURL) { return(new ScalarEnlistment(enlistmentRoot, workingDirectory, string.Empty, gitBinRoot, authentication)); } return(new ScalarEnlistment(enlistmentRoot, workingDirectory, null, gitBinRoot, authentication)); } throw new InvalidRepoException(directory, $"Directory '{directory}' does not exist"); }
// Existing, configured enlistment private GVFSEnlistment(string enlistmentRoot, string gitBinPath, GitAuthentication authentication) : this( enlistmentRoot, null, gitBinPath, authentication) { }
public void Execute(GitAuthentication authentication) { this.ValidatePathParameter(this.EnlistmentRootPathParameter); this.PreCreateEnlistment(); GVFSEnlistment enlistment = this.CreateEnlistment(this.EnlistmentRootPathParameter, authentication); this.Execute(enlistment); }
private GVFSEnlistment CreateEnlistment(string enlistmentRootPath, GitAuthentication authentication) { string gitBinPath = GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath(); if (string.IsNullOrWhiteSpace(gitBinPath)) { this.ReportErrorAndExit("Error: " + GVFSConstants.GitIsNotInstalledError); } string hooksPath = null; if (GVFSPlatform.Instance.UnderConstruction.RequiresDeprecatedGitHooksLoader) { // On Windows, the soon-to-be deprecated GitHooksLoader tries to call out to the hooks process without // its full path, so we have to pass the path along to our background git processes via the PATH // environment variable. On Mac this is not needed because we just copy our own hook directly into // the .git/hooks folder, and once Windows does the same, this hooksPath can be removed (from here // and all the classes that handle it on the way to GitProcess) hooksPath = ProcessHelper.WhereDirectory(GVFSPlatform.Instance.Constants.GVFSHooksExecutableName); if (hooksPath == null) { this.ReportErrorAndExit("Could not find " + GVFSPlatform.Instance.Constants.GVFSHooksExecutableName); } } GVFSEnlistment enlistment = null; try { if (this.validateOriginURL) { enlistment = GVFSEnlistment.CreateFromDirectory(enlistmentRootPath, gitBinPath, hooksPath, authentication); } else { enlistment = GVFSEnlistment.CreateWithoutRepoUrlFromDirectory(enlistmentRootPath, gitBinPath, hooksPath, authentication); } if (enlistment == null) { this.ReportErrorAndExit( "Error: '{0}' is not a valid GVFS enlistment", enlistmentRootPath); } } catch (InvalidRepoException e) { this.ReportErrorAndExit( "Error: '{0}' is not a valid GVFS enlistment. {1}", enlistmentRootPath, e.Message); } return(enlistment); }
public HttpRequestor(ITracer tracer, GitAuthentication authentication) { this.client = new HttpClient(); this.client.Timeout = TimeSpan.FromMinutes(HttpTimeoutMinutes); this.authentication = authentication; this.Tracer = tracer; this.userAgentHeader = new ProductInfoHeaderValue(ProcessHelper.GetEntryClassName(), ProcessHelper.GetCurrentProcessVersion()); }
private GVFSEnlistment CreateEnlistment(string enlistmentRootPath, GitAuthentication authentication) { string gitBinPath = GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath(); if (string.IsNullOrWhiteSpace(gitBinPath)) { this.ReportErrorAndExit("Error: " + GVFSConstants.GitIsNotInstalledError); } string hooksPath; if (GVFSPlatform.Instance.IsUnderConstruction) { hooksPath = "hooksUnderConstruction"; } else { hooksPath = ProcessHelper.WhereDirectory(GVFSPlatform.Instance.Constants.GVFSHooksExecutableName); if (hooksPath == null) { this.ReportErrorAndExit("Could not find " + GVFSPlatform.Instance.Constants.GVFSHooksExecutableName); } } GVFSEnlistment enlistment = null; try { if (this.validateOriginURL) { enlistment = GVFSEnlistment.CreateFromDirectory(enlistmentRootPath, gitBinPath, hooksPath, authentication); } else { enlistment = GVFSEnlistment.CreateWithoutRepoUrlFromDirectory(enlistmentRootPath, gitBinPath, hooksPath, authentication); } if (enlistment == null) { this.ReportErrorAndExit( "Error: '{0}' is not a valid GVFS enlistment", enlistmentRootPath); } } catch (InvalidRepoException e) { this.ReportErrorAndExit( "Error: '{0}' is not a valid GVFS enlistment. {1}", enlistmentRootPath, e.Message); } return(enlistment); }
public HttpRequestor(ITracer tracer, GitAuthentication authentication, int maxConnections) { this.client = new HttpClient(); this.client.Timeout = TimeSpan.FromMinutes(HttpTimeoutMinutes); this.authentication = authentication; this.Tracer = tracer; ServicePointManager.DefaultConnectionLimit = maxConnections; this.userAgentHeader = new ProductInfoHeaderValue(ProcessHelper.GetEntryClassName(), ProcessHelper.GetCurrentProcessVersion()); }
protected Enlistment( string enlistmentRoot, string workingDirectoryRoot, string repoUrl, string gitBinPath, bool flushFileBuffersForPacks, GitAuthentication authentication) { if (string.IsNullOrWhiteSpace(gitBinPath)) { throw new ArgumentException("Path to git.exe must be set"); } this.EnlistmentRoot = enlistmentRoot; this.WorkingDirectoryRoot = workingDirectoryRoot; this.DotGitRoot = Path.Combine(this.WorkingDirectoryRoot, ScalarConstants.DotGit.Root); this.GitBinPath = gitBinPath; this.FlushFileBuffersForPacks = flushFileBuffersForPacks; GitProcess gitProcess = new GitProcess(this); if (repoUrl != null) { this.RepoUrl = repoUrl; } else { GitProcess.ConfigResult originResult = gitProcess.GetOriginUrl(); if (!originResult.TryParseAsString(out string originUrl, out string error)) { if (!gitProcess.TryGetRemotes(out string[] remotes, out error)) { throw new InvalidRepoException(this.WorkingDirectoryRoot, $"Failed to load remotes with error: {error}"); } if (remotes.Length > 0) { GitProcess.ConfigResult remoteResult = gitProcess.GetFromLocalConfig($"remote.{remotes[0]}.url"); if (!remoteResult.TryParseAsString(out originUrl, out error)) { originUrl = null; } } } this.RepoUrl = originUrl?.Trim() ?? string.Empty; } this.Authentication = authentication ?? new GitAuthentication(gitProcess, this.RepoUrl, this.WorkingDirectoryRoot); }
public HttpRequestor(ITracer tracer, RetryConfig retryConfig, GitAuthentication authentication) { this.client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true }); this.client.Timeout = retryConfig.Timeout; this.RetryConfig = retryConfig; this.authentication = authentication; this.Tracer = tracer; this.userAgentHeader = new ProductInfoHeaderValue(ProcessHelper.GetEntryClassName(), ProcessHelper.GetCurrentProcessVersion()); }
protected Enlistment( string enlistmentRoot, string workingDirectoryRoot, string localStorageRoot, string repoUrl, string gitBinPath, string gvfsHooksRoot, bool flushFileBuffersForPacks, GitAuthentication authentication) { if (string.IsNullOrWhiteSpace(gitBinPath)) { throw new ArgumentException("Path to git.exe must be set"); } this.EnlistmentRoot = enlistmentRoot; this.WorkingDirectoryRoot = workingDirectoryRoot; this.WorkingDirectoryBackingRoot = localStorageRoot; this.DotGitRoot = Path.Combine(this.WorkingDirectoryBackingRoot, GVFSConstants.DotGit.Root); this.GitBinPath = gitBinPath; this.GVFSHooksRoot = gvfsHooksRoot; this.FlushFileBuffersForPacks = flushFileBuffersForPacks; GitProcess gitProcess = new GitProcess(this); if (repoUrl != null) { this.RepoUrl = repoUrl; } else { GitProcess.ConfigResult originResult = gitProcess.GetOriginUrl(); if (!originResult.TryParseAsString(out string originUrl, out string error)) { throw new InvalidRepoException("Could not get origin url. git error: " + error); } if (originUrl == null) { throw new InvalidRepoException("Could not get origin url. remote 'origin' is not configured for this repo.'"); } this.RepoUrl = originUrl.Trim(); } this.Authentication = authentication ?? new GitAuthentication(gitProcess, this.RepoUrl); }
public void BackoffIsNotInEffectAfterSuccess() { MockTracer tracer = new MockTracer(); MockGitProcess gitProcess = this.GetGitProcess(); GitAuthentication dut = new GitAuthentication(gitProcess); string authString; string error; for (int i = 0; i < 5; ++i) { dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to get credential on iteration " + i + ": " + error); dut.Revoke(authString); dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to retry getting credential on iteration " + i + ": " + error); dut.ConfirmCredentialsWorked(authString); dut.IsBackingOff.ShouldEqual(false, "Should reset backoff after successfully refreshing credentials"); } }
public void ShouldOnlyRetryAuthOnce() { MockTracer tracer = new MockTracer(); MockEnlistment enlistment = new MockEnlistment(); MockGitProcess gitProcess = new MockGitProcess(enlistment); GitAuthentication dut = new GitAuthentication(gitProcess); string authString; string error; dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to get initial credential"); dut.RevokeAndCheckCanRetry(authString).ShouldEqual(true, "Should retry once"); dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to retry getting credential on iteration"); dut.RevokeAndCheckCanRetry(authString).ShouldEqual(false, "Should not retry more than once"); dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(false, "TryGetCredential should not succeed during backoff"); }
public void GitProcessFailuresAreRetried() { MockTracer tracer = new MockTracer(); MockEnlistment enlistment = new MockEnlistment(); MockGitProcess gitProcess = new MockGitProcess(enlistment); GitAuthentication dut = new GitAuthentication(gitProcess); string authString; string error; gitProcess.ShouldFail = true; dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(false, "Succeeded despite GitProcess returning failure"); dut.RevokeAndCheckCanRetry(authString).ShouldEqual(true, "Should retry once"); gitProcess.ShouldFail = false; dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to get credential on retry"); }
protected HttpRequestor(ITracer tracer, RetryConfig retryConfig, Enlistment enlistment) { this.RetryConfig = retryConfig; this.authentication = enlistment.Authentication; this.Tracer = tracer; HttpClientHandler httpClientHandler = new HttpClientHandler() { UseDefaultCredentials = true }; this.authentication.ConfigureHttpClientHandlerSslIfNeeded(this.Tracer, httpClientHandler, enlistment.CreateGitProcess()); this.client = new HttpClient(httpClientHandler) { Timeout = retryConfig.Timeout }; this.userAgentHeader = new ProductInfoHeaderValue(ProcessHelper.GetEntryClassName(), ProcessHelper.GetCurrentProcessVersion()); }
public void AuthShouldBackoffAfterFirstRetryFailure() { MockTracer tracer = new MockTracer(); MockGitProcess gitProcess = this.GetGitProcess(); GitAuthentication dut = new GitAuthentication(gitProcess); string authString; string error; dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to get initial credential"); dut.Revoke(authString); dut.IsBackingOff.ShouldEqual(false, "Should not backoff after credentials initially revoked"); dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to retry getting credential on iteration"); dut.IsBackingOff.ShouldEqual(false, "Should not backoff after successfully getting credentials"); dut.Revoke(authString); dut.IsBackingOff.ShouldEqual(true, "Should continue to backoff after revoking credentials"); dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(false, "TryGetCredential should not succeed during backoff"); }
public void ContinuesToBackoffIfTryGetCredentialsFails() { MockTracer tracer = new MockTracer(); MockGitProcess gitProcess = this.GetGitProcess(); GitAuthentication dut = new GitAuthentication(gitProcess); string authString; string error; dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to get initial credential"); dut.Revoke(authString); gitProcess.ShouldFail = true; dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(false, "Succeeded despite GitProcess returning failure"); dut.IsBackingOff.ShouldEqual(true, "Should continue to backoff if failed to get credentials"); dut.Revoke(authString); dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(false, "TryGetCredential should not succeed during backoff"); dut.IsBackingOff.ShouldEqual(true, "Should continue to backoff if failed to get credentials"); }
public void GitProcessFailuresAreRetried() { MockTracer tracer = new MockTracer(); MockGitProcess gitProcess = this.GetGitProcess(); GitAuthentication dut = new GitAuthentication(gitProcess); string authString; string error; gitProcess.ShouldFail = true; dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(false, "Succeeded despite GitProcess returning failure"); // Reboke should be a no-op as valid credentials have not been stored dut.Revoke(authString); dut.IsBackingOff.ShouldEqual(false, "Should not backoff if there were no credentials to revoke"); gitProcess.ShouldFail = false; dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to get credential on retry"); }
public void CanRetryManyTimesIfTheresSomeSuccess() { MockTracer tracer = new MockTracer(); MockEnlistment enlistment = new MockEnlistment(); MockGitProcess gitProcess = new MockGitProcess(enlistment); GitAuthentication dut = new GitAuthentication(gitProcess); string authString; string error; for (int i = 0; i < 5; ++i) { dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to get credential on iteration " + i + ": " + error); dut.RevokeAndCheckCanRetry(authString).ShouldEqual(true, "Did not retry after revoke on iteration: " + i); dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to retry getting credential on iteration " + i + ": " + error); dut.ConfirmCredentialsWorked(authString); } }
public void DoesNotRetryIfTryGetCredentialsFails() { MockTracer tracer = new MockTracer(); MockEnlistment enlistment = new MockEnlistment(); MockGitProcess gitProcess = new MockGitProcess(enlistment); GitAuthentication dut = new GitAuthentication(gitProcess); string authString; string error; dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to get initial credential"); dut.RevokeAndCheckCanRetry(authString).ShouldEqual(true, "Should retry once"); gitProcess.ShouldFail = true; dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(false, "Succeeded despite GitProcess returning failure"); dut.RevokeAndCheckCanRetry(authString).ShouldEqual(false, "Should not retry if GitProcess fails after retry"); dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(false, "TryGetCredential should not succeed during backoff"); }
public void TwoThreadsFailAtOnceStillRetriesOnce() { MockTracer tracer = new MockTracer(); MockGitProcess gitProcess = this.GetGitProcess(); GitAuthentication dut = new GitAuthentication(gitProcess); string authString; string error; // Populate an initial PAT on two threads dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true); dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true); // Simulate a 401 error on two threads dut.Revoke(authString); dut.Revoke(authString); // Both threads should still be able to get a PAT for retry purposes dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "The second thread caused back off when it shouldn't"); dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true); }
public void BackoffIsNotInEffectAfterSuccess() { MockTracer tracer = new MockTracer(); MockGitProcess gitProcess = this.GetGitProcess(); GitAuthentication dut = new GitAuthentication(gitProcess, "mock://repoUrl"); dut.TryInitializeAndRequireAuth(tracer, out _); string authString; string error; for (int i = 0; i < 5; ++i) { dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to get credential on iteration " + i + ": " + error); dut.RejectCredentials(tracer, authString); dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to retry getting credential on iteration " + i + ": " + error); dut.ApproveCredentials(tracer, authString); dut.IsBackingOff.ShouldEqual(false, "Should reset backoff after successfully refreshing credentials"); gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(i + 1, $"Should have {i+1} credentials rejection"); gitProcess.CredentialApprovals["mock://repoUrl"].Count.ShouldEqual(i + 1, $"Should have {i+1} credential approvals"); } }