I need to unit test my authentication handler. I don't really want do an assert against the text message returned by the handler. How could this be improved ?
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// Check for API key
if (!request.Headers.Contains(AuthConfig.ApiKeyHeader))
{
return SendResponseText("ApiKey is required");
}
// Check for timestamp
if (request.GetQueryNameValuePairs().Where(k => k.Key.ToLower() == "timestamp").Count() != 1)
{
return SendResponseText("Timestamp is required");
}
// Validate timestamp
if (IsValidTimestamp(request) == false)
{
return SendResponseText("Invalid timeStamp");
}
// Check for signature
if (request.Headers.Authorization == null || request.Headers.Authorization.Scheme != AuthConfig.AuthenticationScheme)
{
return SendResponseText("Signature is required");
}
// Validate API Key
string apikey = request.Headers.GetValues(AuthConfig.ApiKeyHeader).First();
UserDTO user = _userRepo.GetUserAuthInfo(apikey);
if (user == null)
{
return SendResponseText("Invalid API key");
}
// Validate signature
string signature = _signatureCalculator.GetSignature(user.Secret, request.RequestUri.OriginalString);
if (request.Headers.Authorization.Parameter != signature)
{
return SendResponseText("Invalid signature");
}
return base.SendAsync(request, cancellationToken);
}
private Task<HttpResponseMessage> SendResponseText(string text)
{
Logger.Error(text);
var response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
response.ReasonPhrase = text;
response.Content = new StringContent(text);
var tcs = new TaskCompletionSource<HttpResponseMessage>();
tcs.SetResult(response);
return tcs.Task;
}
So far, I have put the custom reason phrases in a constant
public sealed class AuthError
{
public const string ApiKeyMissing = "ApiKey is required";
...
}
And my tests look like this
[TestMethod]
public void SecurityHandler_ApiKeyMissingFromHeader_ReturnsUnauthorizedHttpStatus()
{
var handler = new SecurityHandler(new Mock<IClientRepository>().Object, new Mock<ISignatureCalculator>().Object);
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost");
var client = new HttpClient(handler);
var result = client.SendAsync(httpRequestMessage).Result;
Assert.AreEqual(result.StatusCode, HttpStatusCode.Unauthorized);
Assert.AreEqual(result.ReasonPhrase, SecurityHandler.AuthError.ApiKeyMissing);
}
I'm not too happy with this, and I'm doing 2 asserts which is bad practice.. Any ideas ?