Mock HttpClient with multiple clients to be used in single controller - unit-testing

My unit test is-
String xmlText = File.ReadAllText(#"C:\PrashantWorkspace\Weather.xml");
var mockFactory = new Mock<IHttpClientFactory>();
var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
mockHttpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(xmlText, Encoding.UTF8, "application/xml"),
});
var client = new HttpClient(mockHttpMessageHandler.Object);
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(client);
WeatherController wController = new WeatherController(_logger.Object, _configuration.Object, mockFactory.Object);
var result = await wController.Get("1", "2", false);
Assert.IsType<OkObjectResult>(result);
How can I pass another xml that will be used by 2nd api call in my controller?

If you mean that you have another endpoint (and not the second call to the same endpoint), then you can pass a predicate that will match on the RequestUri of the HttpRequestMessage:
_httpMessageHandlerMock = new Mock<HttpMessageHandler>();
var booksResponse = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(
#"<?xml version=""1.0"" encoding=""utf-8""?> ")
};
_httpMessageHandlerMock
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.Is<HttpRequestMessage>(x =>
x.RequestUri != null && x.RequestUri.ToString().Contains("books")),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(booksResponse);
var authorsResponse = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(
#"<?xml version=""1.0"" encoding=""utf-8""?> ")
};
_httpMessageHandlerMock
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.Is<HttpRequestMessage>(x =>
x.RequestUri != null && x.RequestUri.ToString().Contains("authors")),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(authorsResponse);
_client = new HttpClient(_httpMessageHandlerMock.Object) {BaseAddress = new Uri("http://tempuri")};

Related

Use Aws4RequestSigner to sign PAAPI 5 Request

I'm trying to use Aws4RequestSigner in a VS2015 form to sign a search request to Amazon PAAPI.
https://www.nuget.org/packages/Aws4RequestSigner/
I get this response from the API:
{"__type":"com.amazon.paapi5#IncompleteSignatureException","Errors":[{"Code":"IncompleteSignature","Message":"The request signature did not include all of the required components. If you are using an AWS SDK, requests are signed for you automatically; otherwise, go to https://webservices.amazon.com/paapi5/documentation/sending-request.html#signing."}]}
private async void Form1_Load(object sender, EventArgs e)
{
_accessKey = "x";
_secretKey = "x";
_service = "ProductAdvertisingAPIv1";
_region = "us-east-1";
_requestUri = new Uri("https://webservices.amazon.com/paapi5/searchitems");
var payload = new
{
Keywords = "Harry",
Marketplace = "www.amazon.com",
PartnerTag = "x0d-20",
PartnerType = "Associates",
Resources = new string[] { "Images.Primary.Small", "ItemInfo.Title", "Offers.Listings.Price" },
SearchIndex = "All"
};
string jsonString = JsonConvert.SerializeObject(payload);
var content = new StringContent(jsonString, Encoding.UTF8, "application/json");
var xAmzDate = GetTimeStamp();
content.Headers.Add("content-encoding", "amz-1.0");
content.Headers.Add("x-amz-date", xAmzDate);
content.Headers.Add("x-amz-target", "com.amazon.paapi5.v1.ProductAdvertisingAPIv1.SearchItems");
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = _requestUri,
Content = content
};
request.Headers.Host = "webservices.amazon.com";
var contentType = new MediaTypeHeaderValue("application/json");
contentType.CharSet = "utf-8";
request.Content.Headers.ContentType = contentType;
var signer = new AWS4RequestSigner(_accessKey, _secretKey);
request = await signer.Sign(request, _service, _region);
try
{
var client = new HttpClient();
var response = await client.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
var error = await response.Content.ReadAsStringAsync();
}
// response.EnsureSuccessStatusCode();
txtDisplay.Text = await response.Content.ReadAsStringAsync();
}
catch (HttpRequestException ex)
{
string error = ex.Message;
txtDisplay.Text = error;
}
}
private string GetTimeStamp()
{
return DateTime.UtcNow.ToString("yyyyMMdd\\THHmmss\\Z");
}
It could be that the headers are being added incorrectly or Aws4RequestSigner is simply outdated.

PowerBI Embedded: DeleteUserAsAdminAsync returns unauthorized

Receiving an unauthorized response when trying to remove a user from a workspace (group). I'm using the .Net SDK method DeleteUserAsAdminAsync. I tried the DeleteUserInGroupAsync method with the same result. I've had no trouble retrieving groups, reports, even adding users to groups using the same authentication code shown below. I'm quite stumped.
public async Task<ResultObject> RemoveUsersFromWorkspaces(List<PowerBIWorkspace> powerBIWorkspaces)
{
// Authenticate using created credentials
AuthenticationResult authenticationResult = null;
authenticationResult = await DoAuthentication("CustomerAppRegistration");
var tokenCredentials =
new TokenCredentials(authenticationResult.AccessToken, "Bearer");
using (var client = new PowerBIClient(
new Uri("https://api.powerbi.com/"), tokenCredentials))
{
try
{
foreach (var wksp in powerBIWorkspaces)
{
// Remove the user to the workspace.
await client.Groups.DeleteUserAsAdminAsync(new Guid(wksp.WorkspaceId), wksp.UserEmail);
}
}
catch (Exception ex)
{
var errorObject = new ResultObject();
errorObject.Success = false;
errorObject.ErrorMessage = ex.Message;
return errorObject;
}
}
var resultObject = new ResultObject();
resultObject.Success = true;
resultObject.ErrorMessage = "";
return resultObject;
}
private const string AuthorityFormat = "https://login.microsoftonline.com/{0}/v2.0";
private const string MSGraphScope = "https://analysis.windows.net/powerbi/api/.default";
private async Task<AuthenticationResult> DoAuthentication(string appRegistrationSection)
{
var config = new ConfigurationBuilder()
.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
.AddJsonFile("appsettings.json").Build();
//var section = config.GetSection(nameof(AppRegistration));
var section = config.GetSection(appRegistrationSection);
var appRegistration = section.Get<AppRegistration>();
TenantID = appRegistration.TenantId;
ClientID = appRegistration.ClientId;
ClientSecret = appRegistration.ClientSecret;
IConfidentialClientApplication daemonClient;
daemonClient = ConfidentialClientApplicationBuilder.Create(ClientID)
.WithAuthority(string.Format(AuthorityFormat, TenantID))
.WithClientSecret(ClientSecret)
.Build();
AuthenticationResult authResult =
await daemonClient.AcquireTokenForClient(new[] { MSGraphScope }).ExecuteAsync();
return authResult;
}

Connect to Azure Text Analytics from Console App without await

I am trying to call an Azure API (Text Analytics API) from a C# console application with a HttpRequest and I do not want to use any DLLs or await
but using the below snippet I am receiving "Bad Request". Can someone help me where it is going wrong.
public static void ProcessText()
{
string apiKey = "KEY FROM AZURE";
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var requestUri = "https://eastus.api.cognitive.microsoft.com/text/analytics/v2.0/sentiment?" + queryString;
//HttpResponseMessage response;
// Request body
byte[] byteData = Encoding.UTF8.GetBytes("I really love Azure. It is the best cloud platform");
using (var content = new ByteArrayContent(byteData))
{
//content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = client.PostAsync(requestUri, content).Result;
Console.WriteLine(response);
Console.ReadLine();
}
}
string apiKey = "<<Key from Azure>>";
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var requestUri = "https://**eastus**.api.cognitive.microsoft.com/text/analytics/v2.0/sentiment?" + queryString;
//HttpResponseMessage response;
var body = new
{
documents = new[]
{
new
{
ID="1", text="I really love Azure. It is the best cloud platform"
}
}
};
string json = JsonConvert.SerializeObject(body);
byte[] byteData = Encoding.UTF8.GetBytes(json);
dynamic item = null;
using (var con = new ByteArrayContent(byteData))
{
//content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = client.PostAsync(requestUri, con).Result;
if (response.StatusCode == HttpStatusCode.OK)
{
string res = string.Empty;
using (HttpContent content = response.Content)
{
Task<string> result = content.ReadAsStringAsync();
res = result.Result;
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
item = serializer.Deserialize<object>(res);
}
}
Hi All, I could able to get the API output using the above approach

Testing filters with IDependencyScope in Web API

I have WebApi simple NUnit Test
[Test]
public async Task Test()
{
var attribute = new TestAuthenticationAttribute {ApiVersions = new[] {"v1"}};
System.Web.Http.Controllers.HttpActionContext context = CreateExecutingContext();
var executedContext = new HttpAuthenticationContext(context, null);
const string reasonPhrase = "ReasonPhrase";
const string messagePhrase = "MessagePhrase";
executedContext.ErrorResult = new AuthenticationFailureResult(reasonPhrase, messagePhrase, executedContext.Request);
await attribute.AuthenticateAsync(executedContext, CancellationToken.None);
var errorResult = await executedContext.ErrorResult.ExecuteAsync(new CancellationToken());
Assert.AreEqual(HttpStatusCode.Unauthorized, errorResult.StatusCode);
}
private System.Web.Http.Controllers.HttpActionContext CreateExecutingContext()
{
return new System.Web.Http.Controllers.HttpActionContext { ControllerContext = new HttpControllerContext {Request = new HttpRequestMessage()
{
RequestUri = new Uri("http://TestApi/api/v1/Test")
}}};
}
and in TestAuthenticationAttribute I have
if (context.Request.GetDependencyScope().GetService(typeof(IExternalService)) is IExternalService externalService)
Do some actions;
How to set/resolve IExternalService dependency in test? Do I need e.g. UnityContainer or I can do it without container?
I added HttpConfiguration to my HttpActionContext and now Context.Request.GetDependencyScope() doesn't throw System.NullReferenceException. Of cource ontext.Request.GetDependencyScope().GetService(typeof(IExternalService)) is null, but now It's ok for my tests.
private System.Web.Http.Controllers.HttpActionContext CreateExecutingContext()
{
var config = new HttpConfiguration();
var httpActionContext = new System.Web.Http.Controllers.HttpActionContext
{
ControllerContext = new HttpControllerContext
{
Request = new HttpRequestMessage()
{
RequestUri = new Uri("http://TestApi/api/v1/Test"),
},
Configuration = config
}
};
httpActionContext.ControllerContext.Request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config;
return httpActionContext;
}
If I want to resolve dependency, I will can add DependencyResolver to my config or Mocking framework

ASP.NET Core unit test authorization

I try to create unit testing my authorization logic, but have problem for testing
await this.HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme)));
I have error
No authentication handler is configured to handle the scheme: Cookies
Because he need CookieAuthenticationOptions
But how configuration for unit test I don't know
private static Mock<SignInManager<User>> GetSignInManagerMock(Mock<UserManager<User>> userManagerMock)
{
var context = new Mock<HttpContext>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(x => x.HttpContext).Returns(context.Object);
return new Mock<SignInManager<User>>(userManagerMock.Object,
contextAccessor.Object,
new Mock<IUserClaimsPrincipalFactory<User>>().Object,
new Mock<IOptions<IdentityOptions>>().Object,
new Mock<ILogger<SignInManager<User>>>().Object);
}
private static Mock<UserManager<User>> GetUserManagerMock()
{
return new Mock<UserManager<User>>(new Mock<IUserStore<User>>().Object,
new Mock<IOptions<IdentityOptions>>().Object,
new Mock<IPasswordHasher<User>>().Object,
new IUserValidator<User>[0],
new IPasswordValidator<User>[0],
new Mock<ILookupNormalizer>().Object,
new Mock<IdentityErrorDescriber>().Object,
new Mock<IServiceProvider>().Object,
new Mock<ILogger<UserManager<User>>>().Object);
}
[Fact]
public async void Login_Corect_input_login_password_should_return_ok()
{
var stamp = Guid.NewGuid().ToString();
var user = new User
{
UserName = _fakeUserModel.UserName,
Email = _fakeUserModel.Email,
FirtName = _fakeUserModel.FirstName,
LastName = _fakeUserModel.LastName,
UserPicture = _fakeUserModel.UserPicture,
ConcurrencyStamp = stamp
};
var userManagerMock = GetUserManagerMock();
userManagerMock.Setup(s => s.FindByNameAsync(FakeData.UserName)).ReturnsAsync(user);
userManagerMock.Setup(s => s.GetRolesAsync(user)).ReturnsAsync(FakeData.Roles);
var signInManagerMock = GetSignInManagerMock(userManagerMock);
signInManagerMock.Setup(
s =>
s.PasswordSignInAsync(_fakeCorrectloginModel.UserName, _fakeCorrectloginModel.Password, false,
false))
.ReturnsAsync(Microsoft.AspNetCore.Identity.SignInResult.Success);
var controller = ControllerFactory.CreateFakeController<UserController>(false, userManagerMock.Object,
signInManagerMock.Object);
var response = await controller.Login(_fakeCorrectloginModel);
var result = Assert.IsType<JsonResult>(response);
var getModel = Assert.IsType<UserViewModel>(result.Value);
Assert.Equal(_fakeUserModel, getModel);
}
public static class ControllerFactory
{
public static T CreateFakeController<T>(bool isLoggedIn, params object[] arg) where T : Controller
{
var fakePrincipal = GetPrincipalMock(isLoggedIn).Object;
var fakeActionContext = new ActionContext
{
HttpContext = new DefaultHttpContext
{
User = fakePrincipal
},
ActionDescriptor = new ControllerActionDescriptor(),
RouteData = new RouteData()
};
var controller = (T)Activator.CreateInstance(typeof(T), arg);
controller.ControllerContext = new ControllerContext(fakeActionContext);
return controller;
}
public static Mock<ClaimsPrincipal> GetPrincipalMock(bool isLoggedIn)
{
var principalMock = new Mock<ClaimsPrincipal>();
principalMock.Setup(sg => sg.Identity).Returns(GetIdentityMock(isLoggedIn).Object);
principalMock.Setup(s => s.IsInRole(It.IsAny<string>())).Returns(false);
principalMock.Setup(s => s.Claims).Returns(new List<Claim>
{
GetClaim(HelpClaimTypes.Language, "ua")
});
return principalMock;
}
public static Mock<ClaimsIdentity> GetIdentityMock(bool isLoggedIn)
{
var identityMock = new Mock<ClaimsIdentity>();
identityMock.Setup(sg => sg.AuthenticationType).Returns(isLoggedIn ? FakeData.AuthenticationType : null);
identityMock.Setup(sg => sg.IsAuthenticated).Returns(isLoggedIn);
identityMock.Setup(sg => sg.Name).Returns(isLoggedIn ? FakeData.UserName : null);
return identityMock;
}
public static ClaimsIdentity GetClaimsIdentity(params Claim[] claims)
{
var identityMock = new ClaimsIdentity(claims);
return identityMock;
}
public static Claim GetClaim(string type, string value)
{
return new Claim(type, value);
}
}