Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to Unit test or Mock DefaultAzureCredential Method #20911

Closed
PrakashRajanSakthivel opened this issue May 7, 2021 · 6 comments
Closed

How to Unit test or Mock DefaultAzureCredential Method #20911

PrakashRajanSakthivel opened this issue May 7, 2021 · 6 comments
Assignees
Labels
Azure.Identity Client This issue points to a problem in the data-plane of the library. customer-reported Issues that are reported by GitHub users external to the Azure organization. needs-author-feedback Workflow: More information is needed from author to address the issue. no-recent-activity There has been no recent activity on this issue. question The issue doesn't require a change to the product in order to be resolved. Most issues start as that

Comments

@PrakashRajanSakthivel
Copy link

I am using DefaultAzureCredential to fetch the access token in my function app which has managed identity from azure to authenticate itself to the APIM. so I am using a HttpMessageHandler in that I am checking If the token doesnt exist make a call to Azure and get the token.

Startup in the Function App

public override void Configure(IFunctionsHostBuilder builder)
{
 builder.Services.AddHttpClient(AppConstants.ReplyService)
 //Adding token handler middleware to add authentication related details.
 .AddHttpMessageHandler<AccessTokenHandler>();
}

Handler File:

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 {
 // Use the token to make the call.
 // other details
 request.Headers.Authorization = new AuthenticationHeaderValue(AppConstants.AuthHeader, await GetToken());
  return await base.SendAsync(request, cancellationToken);
 }
 
private async Task<string> GetToken(bool needsRefresh = false)
{
 if (accessTokenCache.GetCount() == 0 || needsRefresh)
 {
  var tokenCredential = new DefaultAzureCredential();
  var accessToken = await tokenCredential.GetTokenAsync(
  new TokenRequestContext(scopes: new string[] { _config["AppId"] + "/.default" }) { });
   accessTokenCache.Set("accessToken", accessToken.Token, DateTimeOffset.Now.AddMinutes(55));
     }
     return accessTokenCache.Get("accessToken")?.ToString() ?? throw new Exception("Unable to Fetch Access Token from Cache");
    }

Is there any way I can inject the new AzureDefaultCredentail Method so that I can mock it or pass on like IHttpClientFactory to inject it? I dont find much reference on the unit testin part

@ghost ghost added needs-triage Workflow: This is a new issue that needs to be triaged to the appropriate team. customer-reported Issues that are reported by GitHub users external to the Azure organization. question The issue doesn't require a change to the product in order to be resolved. Most issues start as that labels May 7, 2021
@jsquire jsquire added Azure.Identity needs-team-attention Workflow: This issue needs attention from Azure service team or SDK team labels May 7, 2021
@ghost ghost removed the needs-triage Workflow: This is a new issue that needs to be triaged to the appropriate team. label May 7, 2021
@jsquire
Copy link
Member

jsquire commented May 7, 2021

Thank you for your feedback. Tagging and routing to the team members best able to assist.

@jsquire jsquire added the Client This issue points to a problem in the data-plane of the library. label May 10, 2021
@christothes
Copy link
Member

Hi @PrakashRajanSakthivel - If you need to mock DefaultAzureCredential, I'd recommend something like Moq. For example:

var dacMock = new Mock<DefaultAzureCredential>();
int i = 0;
dacMock
    .Setup(m => m.GetToken(It.IsAny<TokenRequestContext>(), It.IsAny<CancellationToken>()))
    .Callback (() => i++);

var dac = dacMock.Object;
dac.GetToken(new TokenRequestContext());
Console.WriteLine(i.ToString());

@christothes christothes added the needs-author-feedback Workflow: More information is needed from author to address the issue. label May 10, 2021
@ghost ghost removed the needs-team-attention Workflow: This issue needs attention from Azure service team or SDK team label May 10, 2021
@ghost ghost added the no-recent-activity There has been no recent activity on this issue. label May 18, 2021
@ghost
Copy link

ghost commented May 18, 2021

Hi, we're sending this friendly reminder because we haven't heard back from you in 7 days. We need more information about this issue to help address it. Please be sure to give us your input. If we don't hear back from you within 14 days of this comment the issue will be automatically closed. Thank you!

@PrakashRajanSakthivel
Copy link
Author

Thanks, @christothes , Is that something I can inject into my class so that it gets picked up? like in my example above

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 {
 // Use the token to make the call.
 // other details
 request.Headers.Authorization = new AuthenticationHeaderValue(AppConstants.AuthHeader, await GetToken());
  return await base.SendAsync(request, cancellationToken);
 }

private async Task<string> GetToken(bool needsRefresh = false)
{
 if (accessTokenCache.GetCount() == 0 || needsRefresh)
 {
// Instead of creating a new instance?
  var tokenCredential = new DefaultAzureCredential();
  var accessToken = await tokenCredential.GetTokenAsync(
  new TokenRequestContext(scopes: new string[] { _config["AppId"] + "/.default" }) { });
   accessTokenCache.Set("accessToken", accessToken.Token, DateTimeOffset.Now.AddMinutes(55));
     }
     return accessTokenCache.Get("accessToken")?.ToString() ?? throw new Exception("Unable to Fetch Access Token from Cache");
    }

@ghost ghost added needs-team-attention Workflow: This issue needs attention from Azure service team or SDK team and removed needs-author-feedback Workflow: More information is needed from author to address the issue. no-recent-activity There has been no recent activity on this issue. labels May 27, 2021
@christothes
Copy link
Member

As long as it gets invoked sometime before you attempt to call GetToken, it would be up to you how to call it. In my simple repro, I just called it at the beginning of the function invoke. Since it is static it does not need to be injected.

@christothes christothes added the needs-author-feedback Workflow: More information is needed from author to address the issue. label May 27, 2021
@ghost ghost removed the needs-team-attention Workflow: This issue needs attention from Azure service team or SDK team label May 27, 2021
@ghost ghost added the no-recent-activity There has been no recent activity on this issue. label Jun 3, 2021
@ghost
Copy link

ghost commented Jun 3, 2021

Hi, we're sending this friendly reminder because we haven't heard back from you in 7 days. We need more information about this issue to help address it. Please be sure to give us your input. If we don't hear back from you within 14 days of this comment the issue will be automatically closed. Thank you!

@ghost ghost closed this as completed Jun 18, 2021
@github-actions github-actions bot locked and limited conversation to collaborators Mar 27, 2023
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Azure.Identity Client This issue points to a problem in the data-plane of the library. customer-reported Issues that are reported by GitHub users external to the Azure organization. needs-author-feedback Workflow: More information is needed from author to address the issue. no-recent-activity There has been no recent activity on this issue. question The issue doesn't require a change to the product in order to be resolved. Most issues start as that
Projects
None yet
Development

No branches or pull requests

4 participants