Skip to content

Commit

Permalink
Fix dab validate schema fetch Error from URL (#2099)
Browse files Browse the repository at this point in the history
## Why make this change?

- Closes #2013
- An error is thrown when NJsonSchema tries to fetch the schema from
url, due to failing to add refrences.

## What is this change?

- since, we only need to fetch the data from the schema file, we can
simply make a get call to the url, instead of using NJsonSchema.

## How was this tested?

- [ ] Integration Tests
- [ ] Unit Tests

## Sample Request(s)

- Example REST and/or GraphQL request to demonstrate modifications
- Example of CLI usage to demonstrate modifications
  • Loading branch information
abhishekkumams committed Mar 25, 2024
1 parent 5de3682 commit 8c95d76
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 5 deletions.
22 changes: 17 additions & 5 deletions src/Core/Configurations/JsonConfigSchemaValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,19 @@ public class JsonConfigSchemaValidator
{
private ILogger<JsonConfigSchemaValidator> _logger;
private IFileSystem _fileSystem;
private HttpClient _httpClient;

/// <summary>
/// Sets the logger and file system for the JSON config schema validator.
/// Sets the logger, file system and httpClient for the JSON config schema validator.
/// </summary>
/// <param name="jsonSchemaValidatorLogger">The logger to use for the JSON schema validator.</param>
/// <param name="fileSystem">The file system to use for the JSON schema validator.</param>
public JsonConfigSchemaValidator(ILogger<JsonConfigSchemaValidator> jsonSchemaValidatorLogger, IFileSystem fileSystem)
/// <param name="httpClient">The http client to use for the JSON schema validator. If not provided, a new HttpClient will be used.</param>
public JsonConfigSchemaValidator(ILogger<JsonConfigSchemaValidator> jsonSchemaValidatorLogger, IFileSystem fileSystem, HttpClient? httpClient = null)
{
_logger = jsonSchemaValidatorLogger;
_fileSystem = fileSystem;
_httpClient = httpClient ?? new();
}

/// <summary>
Expand Down Expand Up @@ -71,12 +74,21 @@ public async Task<JsonSchemaValidationResult> ValidateJsonConfigWithSchemaAsync(
{
try
{
JsonSchema jsonSchema = await JsonSchema.FromUrlAsync(runtimeConfig.Schema);
return jsonSchema.ToJson();
// Send a GET request to the URL specified in runtimeConfig.Schema to get the JSON schema.
HttpResponseMessage response = await _httpClient.GetAsync(runtimeConfig.Schema);
if (response.IsSuccessStatusCode)
{
string jsonSchema = await response.Content.ReadAsStringAsync();
return jsonSchema;
}
else
{
_logger!.LogWarning($"Received response: ({response.StatusCode}) while fetching schema from url: {runtimeConfig.Schema}");
}
}
catch (Exception e)
{
_logger!.LogError($"Failed to get schema from url: {runtimeConfig.Schema}\n{e}");
_logger!.LogWarning($"Failed to send GET request to fetch schema from url: {runtimeConfig.Schema}\n{e}");
}
}

Expand Down
96 changes: 96 additions & 0 deletions src/Service.Tests/Configuration/ConfigurationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
using Microsoft.IdentityModel.Tokens;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Moq.Protected;
using VerifyMSTest;
using static Azure.DataApiBuilder.Config.FileSystemRuntimeConfigLoader;
using static Azure.DataApiBuilder.Service.Tests.Configuration.ConfigurationEndpoints;
Expand Down Expand Up @@ -1323,6 +1324,101 @@ public async Task TestEngineCanStartConfigWithCustomProperties()
}
}

/// <summary>
/// This test checks that the GetJsonSchema method of the JsonConfigSchemaValidator class
/// correctly downloads a JSON schema from a given URL, and that the downloaded schema matches the expected schema.
/// </summary>
[TestMethod]
public async Task GetJsonSchema_DownloadsSchemaFromUrl()
{
// Arrange
Mock<HttpMessageHandler> handlerMock = new(MockBehavior.Strict);
string jsonSchemaContent = "{\"type\": \"object\", \"properties\": {\"property1\": {\"type\": \"string\"}}}";
handlerMock
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>()
)
.ReturnsAsync(new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(jsonSchemaContent, Encoding.UTF8, "application/json"),
})
.Verifiable();

HttpClient mockHttpClient = new(handlerMock.Object);
Mock<ILogger<JsonConfigSchemaValidator>> schemaValidatorLogger = new();
JsonConfigSchemaValidator jsonConfigSchemaValidator = new(schemaValidatorLogger.Object, new MockFileSystem(), mockHttpClient);

string url = "http://example.com/schema.json";
RuntimeConfig runtimeConfig = new(
Schema: url,
DataSource: new(DatabaseType.MSSQL, "connectionString", null),
new RuntimeEntities(new Dictionary<string, Entity>())
);

// Act
string receivedJsonSchema = await jsonConfigSchemaValidator.GetJsonSchema(runtimeConfig);

// Assert
Assert.AreEqual(jsonSchemaContent, receivedJsonSchema);
handlerMock.Protected().Verify(
"SendAsync",
Times.Exactly(1),
ItExpr.Is<HttpRequestMessage>(req =>
req.Method == HttpMethod.Get
&& req.RequestUri == new Uri(url)),
ItExpr.IsAny<CancellationToken>());
}

/// <summary>
/// This test checks that even when the schema download fails, the GetJsonSchema method
/// fetches the schema from the package succesfully.
/// </summary>
[TestMethod]
public async Task GetJsonSchema_DownloadsSchemaFromUrlFailure()
{
// Arrange
Mock<HttpMessageHandler> handlerMock = new(MockBehavior.Strict);
handlerMock
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>()
)
.ReturnsAsync(new HttpResponseMessage()
{
StatusCode = HttpStatusCode.InternalServerError, // Simulate a failure
Content = new StringContent("", Encoding.UTF8, "application/json"),
})
.Verifiable();

HttpClient mockHttpClient = new(handlerMock.Object);
Mock<ILogger<JsonConfigSchemaValidator>> schemaValidatorLogger = new();
JsonConfigSchemaValidator jsonConfigSchemaValidator = new(schemaValidatorLogger.Object, new MockFileSystem(), mockHttpClient);

string url = "http://example.com/schema.json";
RuntimeConfig runtimeConfig = new(
Schema: url,
DataSource: new(DatabaseType.MSSQL, "connectionString", null),
new RuntimeEntities(new Dictionary<string, Entity>())
);

// Act
string receivedJsonSchema = await jsonConfigSchemaValidator.GetJsonSchema(runtimeConfig);

// Assert
Assert.IsFalse(string.IsNullOrEmpty(receivedJsonSchema));

// Sanity check to ensure the schema is valid
Assert.IsTrue(receivedJsonSchema.Contains("$schema"));
Assert.IsTrue(receivedJsonSchema.Contains("data-source"));
Assert.IsTrue(receivedJsonSchema.Contains("entities"));
}

/// <summary>
/// Set the connection string to an invalid value and expect the service to be unavailable
/// since without this env var, it would be available - guaranteeing this env variable
Expand Down

0 comments on commit 8c95d76

Please sign in to comment.