mirror of
https://github.com/bitwarden/server
synced 2025-12-16 16:23:31 +00:00
PM-25413 no badRequest result because of error from Onyx (#6285)
This commit is contained in:
@@ -152,6 +152,12 @@ public class FreshdeskController : Controller
|
|||||||
return new BadRequestResult();
|
return new BadRequestResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if there is no description, then we don't send anything to onyx
|
||||||
|
if (string.IsNullOrEmpty(model.TicketDescriptionText.Trim()))
|
||||||
|
{
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
// create the onyx `answer-with-citation` request
|
// create the onyx `answer-with-citation` request
|
||||||
var onyxRequestModel = new OnyxAnswerWithCitationRequestModel(model.TicketDescriptionText, _billingSettings.Onyx.PersonaId);
|
var onyxRequestModel = new OnyxAnswerWithCitationRequestModel(model.TicketDescriptionText, _billingSettings.Onyx.PersonaId);
|
||||||
var onyxRequest = new HttpRequestMessage(HttpMethod.Post,
|
var onyxRequest = new HttpRequestMessage(HttpMethod.Post,
|
||||||
@@ -164,9 +170,12 @@ public class FreshdeskController : Controller
|
|||||||
// the CallOnyxApi will return a null if we have an error response
|
// the CallOnyxApi will return a null if we have an error response
|
||||||
if (onyxJsonResponse?.Answer == null || !string.IsNullOrEmpty(onyxJsonResponse?.ErrorMsg))
|
if (onyxJsonResponse?.Answer == null || !string.IsNullOrEmpty(onyxJsonResponse?.ErrorMsg))
|
||||||
{
|
{
|
||||||
return BadRequest(
|
_logger.LogWarning("Error getting answer from Onyx AI. Freshdesk model: {model}\r\n Onyx query {query}\r\nresponse: {response}. ",
|
||||||
string.Format("Failed to get a valid response from Onyx API. Response: {0}",
|
JsonSerializer.Serialize(model),
|
||||||
JsonSerializer.Serialize(onyxJsonResponse ?? new OnyxAnswerWithCitationResponseModel())));
|
JsonSerializer.Serialize(onyxRequestModel),
|
||||||
|
JsonSerializer.Serialize(onyxJsonResponse));
|
||||||
|
|
||||||
|
return Ok(); // return ok so we don't retry
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the answer as a note to the ticket
|
// add the answer as a note to the ticket
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using Bit.Test.Common.AutoFixture;
|
|||||||
using Bit.Test.Common.AutoFixture.Attributes;
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using NSubstitute;
|
using NSubstitute;
|
||||||
using NSubstitute.ReceivedExtensions;
|
using NSubstitute.ReceivedExtensions;
|
||||||
@@ -126,7 +127,7 @@ public class FreshdeskControllerTests
|
|||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[BitAutoData(WebhookKey)]
|
[BitAutoData(WebhookKey)]
|
||||||
public async Task PostWebhookOnyxAi_invalid_onyx_response_results_in_BadRequest(
|
public async Task PostWebhookOnyxAi_invalid_onyx_response_results_is_logged(
|
||||||
string freshdeskWebhookKey, FreshdeskOnyxAiWebhookModel model,
|
string freshdeskWebhookKey, FreshdeskOnyxAiWebhookModel model,
|
||||||
SutProvider<FreshdeskController> sutProvider)
|
SutProvider<FreshdeskController> sutProvider)
|
||||||
{
|
{
|
||||||
@@ -150,8 +151,18 @@ public class FreshdeskControllerTests
|
|||||||
|
|
||||||
var response = await sutProvider.Sut.PostWebhookOnyxAi(freshdeskWebhookKey, model);
|
var response = await sutProvider.Sut.PostWebhookOnyxAi(freshdeskWebhookKey, model);
|
||||||
|
|
||||||
var result = Assert.IsAssignableFrom<BadRequestObjectResult>(response);
|
var statusCodeResult = Assert.IsAssignableFrom<StatusCodeResult>(response);
|
||||||
Assert.Equal(StatusCodes.Status400BadRequest, result.StatusCode);
|
Assert.Equal(StatusCodes.Status200OK, statusCodeResult.StatusCode);
|
||||||
|
|
||||||
|
var _logger = sutProvider.GetDependency<ILogger<FreshdeskController>>();
|
||||||
|
|
||||||
|
// workaround because _logger.Received(1).LogWarning(...) does not work
|
||||||
|
_logger.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Log" && c.GetArguments()[1].ToString().Contains("Error getting answer from Onyx AI"));
|
||||||
|
|
||||||
|
// sent call to Onyx API - but we got an error response
|
||||||
|
_ = mockOnyxHttpMessageHandler.Received(1).Send(Arg.Any<HttpRequestMessage>(), Arg.Any<CancellationToken>());
|
||||||
|
// did not call freshdesk to add a note since onyx failed
|
||||||
|
_ = mockFreshdeskHttpMessageHandler.DidNotReceive().Send(Arg.Any<HttpRequestMessage>(), Arg.Any<CancellationToken>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -174,10 +185,9 @@ public class FreshdeskControllerTests
|
|||||||
.Returns(mockFreshdeskAddNoteResponse);
|
.Returns(mockFreshdeskAddNoteResponse);
|
||||||
var freshdeskHttpClient = new HttpClient(mockFreshdeskHttpMessageHandler);
|
var freshdeskHttpClient = new HttpClient(mockFreshdeskHttpMessageHandler);
|
||||||
|
|
||||||
|
|
||||||
// mocking Onyx api response given a ticket description
|
// mocking Onyx api response given a ticket description
|
||||||
var mockOnyxHttpMessageHandler = Substitute.ForPartsOf<MockHttpMessageHandler>();
|
var mockOnyxHttpMessageHandler = Substitute.ForPartsOf<MockHttpMessageHandler>();
|
||||||
onyxResponse.ErrorMsg = string.Empty;
|
onyxResponse.ErrorMsg = "string.Empty";
|
||||||
var mockOnyxResponse = new HttpResponseMessage(System.Net.HttpStatusCode.OK)
|
var mockOnyxResponse = new HttpResponseMessage(System.Net.HttpStatusCode.OK)
|
||||||
{
|
{
|
||||||
Content = new StringContent(JsonSerializer.Serialize(onyxResponse))
|
Content = new StringContent(JsonSerializer.Serialize(onyxResponse))
|
||||||
@@ -195,6 +205,37 @@ public class FreshdeskControllerTests
|
|||||||
Assert.Equal(StatusCodes.Status200OK, result.StatusCode);
|
Assert.Equal(StatusCodes.Status200OK, result.StatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData(WebhookKey)]
|
||||||
|
public async Task PostWebhookOnyxAi_ticket_description_is_empty_return_success(
|
||||||
|
string freshdeskWebhookKey, FreshdeskOnyxAiWebhookModel model,
|
||||||
|
SutProvider<FreshdeskController> sutProvider)
|
||||||
|
{
|
||||||
|
var billingSettings = sutProvider.GetDependency<IOptions<BillingSettings>>().Value;
|
||||||
|
billingSettings.FreshDesk.WebhookKey.Returns(freshdeskWebhookKey);
|
||||||
|
billingSettings.Onyx.BaseUrl.Returns("http://simulate-onyx-api.com/api");
|
||||||
|
|
||||||
|
model.TicketDescriptionText = " "; // empty description
|
||||||
|
|
||||||
|
// mocking freshdesk api add note request (POST)
|
||||||
|
var mockFreshdeskHttpMessageHandler = Substitute.ForPartsOf<MockHttpMessageHandler>();
|
||||||
|
var freshdeskHttpClient = new HttpClient(mockFreshdeskHttpMessageHandler);
|
||||||
|
|
||||||
|
// mocking Onyx api response given a ticket description
|
||||||
|
var mockOnyxHttpMessageHandler = Substitute.ForPartsOf<MockHttpMessageHandler>();
|
||||||
|
var onyxHttpClient = new HttpClient(mockOnyxHttpMessageHandler);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IHttpClientFactory>().CreateClient("FreshdeskApi").Returns(freshdeskHttpClient);
|
||||||
|
sutProvider.GetDependency<IHttpClientFactory>().CreateClient("OnyxApi").Returns(onyxHttpClient);
|
||||||
|
|
||||||
|
var response = await sutProvider.Sut.PostWebhookOnyxAi(freshdeskWebhookKey, model);
|
||||||
|
|
||||||
|
var result = Assert.IsAssignableFrom<OkResult>(response);
|
||||||
|
Assert.Equal(StatusCodes.Status200OK, result.StatusCode);
|
||||||
|
_ = mockFreshdeskHttpMessageHandler.DidNotReceive().Send(Arg.Any<HttpRequestMessage>(), Arg.Any<CancellationToken>());
|
||||||
|
_ = mockOnyxHttpMessageHandler.DidNotReceive().Send(Arg.Any<HttpRequestMessage>(), Arg.Any<CancellationToken>());
|
||||||
|
}
|
||||||
|
|
||||||
public class MockHttpMessageHandler : HttpMessageHandler
|
public class MockHttpMessageHandler : HttpMessageHandler
|
||||||
{
|
{
|
||||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||||
|
|||||||
Reference in New Issue
Block a user