Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 41 additions & 19 deletions src/Config/Entity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public void TryPopulateSourceFields()
}
else
{
ObjectType = ConvertSourceType(objectSource.Type);
ObjectType = objectSource.Type;
SourceName = objectSource.Name;
Parameters = objectSource.Parameters;
KeyFields = objectSource.KeyFields;
Expand All @@ -165,23 +165,6 @@ public void TryPopulateSourceFields()
throw new JsonException(message: $"Source not one of string or object");
}
}

/// <summary>
/// Tries to convert the given string sourceType into one of the supported SourceType enums
/// Throws an exception if not a case-insensitive match
/// </summary>
private static SourceType ConvertSourceType(string? sourceType)
{
// If sourceType is not explicitly specified, we assume it is a Table
return sourceType is null ? SourceType.Table
: sourceType.ToLowerInvariant() switch
{
"table" => SourceType.Table,
"view" => SourceType.View,
"stored-procedure" => SourceType.StoredProcedure,
_ => throw new JsonException(message: "Source type must be one of: [table, view, stored-procedure]")
};
}
}

/// <summary>
Expand All @@ -196,13 +179,52 @@ private static SourceType ConvertSourceType(string? sourceType)
/// <param name="KeyFields"> The field(s) to be used as primary keys.
/// Support tracked in #547 </param>
public record DatabaseObjectSource(
string Type,
[property: JsonConverter(typeof(SourceTypeEnumJsonConverter))]
SourceType Type,
[property: JsonPropertyName("object")]
string Name,
Dictionary<string, object>? Parameters,
[property: JsonPropertyName("key-fields")]
Array KeyFields);

/// <summary>
/// Class to specify custom converter used while deserialising json config
/// to SourceType and serializing from SourceType to string.
/// Tries to convert the given string sourceType into one of the supported SourceType enums
/// Throws an exception if not a case-insensitive match
/// </summary>
public class SourceTypeEnumJsonConverter : JsonConverter<SourceType>
{
public const string STORED_PROCEDURE = "stored-procedure";

/// <inheritdoc/>
public override SourceType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
string? type = reader.GetString();
if (STORED_PROCEDURE.Equals(type))
{
return SourceType.StoredProcedure;
}

if (Enum.TryParse<SourceType>(type, ignoreCase: true, out SourceType sourceType))
{
return sourceType;
}
else
{
throw new JsonException($"Invalid Source Type: {type}." +
$" Valid values are {STORED_PROCEDURE}, {SourceType.Table}, and {SourceType.View}.");
}
}

/// <inheritdoc/>
public override void Write(Utf8JsonWriter writer, SourceType value, JsonSerializerOptions options)
{
string valueToWrite = value is SourceType.StoredProcedure ? STORED_PROCEDURE : value.ToString().ToLower();
writer.WriteStringValue(valueToWrite);
}
}
Comment thread
abhishekkumams marked this conversation as resolved.

/// <summary>
/// Supported source types as defined by json schema
/// </summary>
Expand Down
7 changes: 6 additions & 1 deletion src/Service.Tests/Authorization/AuthorizationHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public static AuthorizationResolver InitAuthorizationResolver(RuntimeConfig runt
/// <returns></returns>
public static RuntimeConfig InitRuntimeConfig(
string entityName = TEST_ENTITY,
string entitySource = TEST_ENTITY,
object? entitySource = null,
string roleName = "Reader",
Operation operation = Operation.Create,
HashSet<string>? includedCols = null,
Expand All @@ -69,6 +69,11 @@ public static RuntimeConfig InitRuntimeConfig(
{
Field? fieldsForRole = null;

if (entitySource is null)
Comment thread
abhishekkumams marked this conversation as resolved.
{
entitySource = TEST_ENTITY;
}

if (includedCols is not null || excludedCols is not null)
{
// Only create object for Fields if inc/exc cols is not null.
Expand Down
70 changes: 70 additions & 0 deletions src/Service.Tests/Configuration/ConfigurationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,76 @@ public async Task TestNoConfigReturnsServiceUnavailable(string[] args)
Assert.AreEqual(HttpStatusCode.ServiceUnavailable, result.StatusCode);
}

/// <summary>
/// Checks correct serialization and deserialization of Source Type from
/// Enum to String and vice-versa.
/// Consider both cases for source as an object and as a string
/// </summary>
[DataTestMethod]
[DataRow(true, SourceType.StoredProcedure, "stored-procedure", DisplayName = "source is a stored-procedure")]
[DataRow(true, SourceType.Table, "table", DisplayName = "source is a table")]
[DataRow(true, SourceType.View, "view", DisplayName = "source is a view")]
[DataRow(false, null, null, DisplayName = "source is just string")]
public void TestCorrectSerializationOfSourceObject(
Comment thread
abhishekkumams marked this conversation as resolved.
bool isDatabaseObjectSource,
SourceType sourceObjectType,
string sourceTypeName)
{
object entitySource;
if (isDatabaseObjectSource)
{
entitySource = new DatabaseObjectSource(
Type: sourceObjectType,
Name: "sourceName",
Parameters: null,
KeyFields: null
);
}
else
{
entitySource = "sourceName";
}

RuntimeConfig runtimeConfig = AuthorizationHelpers.InitRuntimeConfig(
entityName: "MyEntity",
entitySource: entitySource,
roleName: "Anonymous",
operation: Operation.All,
includedCols: null,
excludedCols: null,
databasePolicy: null
);

string runtimeConfigJson = JsonSerializer.Serialize<RuntimeConfig>(runtimeConfig);

if (isDatabaseObjectSource)
{
Assert.IsTrue(runtimeConfigJson.Contains(sourceTypeName));
}

Mock<ILogger> logger = new();
Assert.IsTrue(RuntimeConfig.TryGetDeserializedConfig(
runtimeConfigJson,
out RuntimeConfig deserializedRuntimeConfig,
logger.Object));

Assert.IsTrue(deserializedRuntimeConfig.Entities.ContainsKey("MyEntity"));
deserializedRuntimeConfig.Entities["MyEntity"].TryPopulateSourceFields();
Assert.AreEqual("sourceName", deserializedRuntimeConfig.Entities["MyEntity"].SourceName);

JsonElement sourceJson = (JsonElement)deserializedRuntimeConfig.Entities["MyEntity"].Source;
if (isDatabaseObjectSource)
{
Assert.AreEqual(JsonValueKind.Object, sourceJson.ValueKind);
Assert.AreEqual(sourceObjectType, deserializedRuntimeConfig.Entities["MyEntity"].ObjectType);
}
else
{
Assert.AreEqual(JsonValueKind.String, sourceJson.ValueKind);
Assert.AreEqual("sourceName", deserializedRuntimeConfig.Entities["MyEntity"].Source.ToString());
}
}

[TestMethod("Validates that once the configuration is set, the config controller isn't reachable.")]
public async Task TestConflictAlreadySetConfiguration()
{
Expand Down