-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added avro schema support * Added MessageSerializer
- Loading branch information
Showing
10 changed files
with
285 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
using System.Collections.Concurrent; | ||
using System.Text; | ||
using GraphQL.Types; | ||
using Memphis.Client.Exception; | ||
using Memphis.Client.UnitTests.Validators.TestData; | ||
using Memphis.Client.Validators; | ||
using Xunit; | ||
|
||
namespace Memphis.Client.UnitTests.Validators; | ||
|
||
public class AvroValidatorTest | ||
{ | ||
|
||
|
||
private readonly ISchemaValidator _validator; | ||
|
||
public AvroValidatorTest() | ||
{ | ||
_validator = new AvroValidator(); | ||
} | ||
|
||
#region AvroValidatorTest.ParseAndStore | ||
[Theory] | ||
[MemberData(nameof(AvroValidatorTestData.ValidSchema), MemberType = typeof(AvroValidatorTestData))] | ||
public void ShouldReturnTrue_WhenParseAndStore_WhereValidSchemaPassed(string validSchema) | ||
{ | ||
var actual = _validator.ParseAndStore("vaid-schema-001", validSchema); | ||
|
||
Assert.True(actual); | ||
} | ||
|
||
|
||
[Theory] | ||
[MemberData(nameof(AvroValidatorTestData.InvalidSchema), MemberType = typeof(AvroValidatorTestData))] | ||
public void ShouldReturnFalse_WhenParseAndStore_WhereInvalidSchemaPassed(string invalidSchema) | ||
{ | ||
var actual = _validator.ParseAndStore("invalid-schema-001", invalidSchema); | ||
|
||
Assert.False(actual); | ||
} | ||
|
||
#endregion | ||
|
||
|
||
#region AvroValidatorTest.ValidateAsync | ||
|
||
[Theory] | ||
[MemberData(nameof(AvroValidatorTestData.ValidSchemaDetail), MemberType = typeof(AvroValidatorTestData))] | ||
public async Task ShouldDoSuccess_WhenValidateAsync_WhereValidDataPassed(string schemaKey, string schema, byte[] msg) | ||
{ | ||
_validator.ParseAndStore(schemaKey, schema); | ||
|
||
var exception = await Record.ExceptionAsync(async () => await _validator.ValidateAsync(msg, schemaKey)); | ||
|
||
Assert.Null(exception); | ||
} | ||
|
||
[Theory] | ||
[MemberData(nameof(AvroValidatorTestData.InvalidSchemaDetail), MemberType = typeof(AvroValidatorTestData))] | ||
public async Task ShouldDoThrow_WhenValidateAsync_WhereInvalidDataPassed(string schemaKey, string schema, byte[] msg) | ||
{ | ||
_validator.ParseAndStore(schemaKey, schema); | ||
|
||
await Assert.ThrowsAsync<MemphisSchemaValidationException>( | ||
() => _validator.ValidateAsync(msg, schemaKey)); | ||
} | ||
|
||
[Theory] | ||
[MemberData(nameof(AvroValidatorTestData.Message), MemberType = typeof(AvroValidatorTestData))] | ||
public async Task ShouldDoThrow_WhenValidateAsync_WhereSchemaNotFoundInCache(byte[] msg) | ||
{ | ||
var nonexistentSchema = Guid.NewGuid().ToString(); | ||
|
||
await Assert.ThrowsAsync<MemphisSchemaValidationException>( | ||
() => _validator.ValidateAsync(msg, nonexistentSchema)); | ||
} | ||
|
||
#endregion | ||
} |
75 changes: 75 additions & 0 deletions
75
src/Memphis.Client.UnitTests/Validators/TestData/AvroValidatorTestData.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
using System.ComponentModel; | ||
using System.Runtime.Serialization; | ||
using System.Text; | ||
using SolTechnology.Avro; | ||
using SolTechnology.Avro.Infrastructure.Attributes; | ||
|
||
namespace Memphis.Client.UnitTests; | ||
|
||
|
||
public class ValidUserModel | ||
{ | ||
[DataMember(Name = "name")] | ||
public string Name { get; set; } = null!; | ||
|
||
[DataMember(Name = "age")] | ||
public long Age { get; set; } | ||
} | ||
|
||
public class InvalidUserModel | ||
{ | ||
|
||
[DataMember(Name = "email")] | ||
public string Email { get; set; } = null!; | ||
} | ||
|
||
|
||
public class AvroValidatorTestData | ||
{ | ||
public static List<object[]> ValidSchema => new() | ||
{ | ||
new object[] { validUser }, | ||
}; | ||
|
||
public static List<object[]> InvalidSchema => new() | ||
{ | ||
new object[] { invalidSch1 }, | ||
}; | ||
|
||
public static List<object[]> Message => new() | ||
{ | ||
new object[] { validUserData }, | ||
}; | ||
|
||
public static List<object[]> ValidSchemaDetail => new() | ||
{ | ||
new object[] { "valid-simple-msg", validUser, validUserData }, | ||
}; | ||
|
||
public static List<object[]> InvalidSchemaDetail => new() | ||
{ | ||
new object[] { "invalid-simple-msg", validUser, invalidMsg }, | ||
}; | ||
|
||
|
||
private static readonly string validUser = AvroConvert.GenerateSchema(typeof(ValidUserModel)); | ||
|
||
|
||
private const string invalidSch1 = "This is invalid avro schema"; | ||
|
||
|
||
private readonly static byte[] validUserData = AvroConvert.Serialize(new ValidUserModel | ||
{ | ||
Name = "John Doe", | ||
Age = 30 | ||
}); | ||
|
||
|
||
private readonly static byte[] invalidMsg = AvroConvert.Serialize(new InvalidUserModel | ||
{ | ||
Email = "[email protected]" | ||
}); | ||
|
||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
using System; | ||
using System.IO; | ||
using System.Text; | ||
using Memphis.Client.Constants; | ||
using Memphis.Client.Exception; | ||
using Newtonsoft.Json; | ||
using SolTechnology.Avro; | ||
|
||
namespace Memphis.Client; | ||
|
||
public class MessageSerializer | ||
{ | ||
/// <summary> | ||
/// Serialize the object to the specified schema type. The supported schema types are: json, graphql, protobuf, avro | ||
/// </summary> | ||
/// <typeparam name="T"></typeparam> | ||
/// <param name="obj"></param> | ||
/// <param name="schemaType"></param> | ||
/// <returns></returns> | ||
/// <exception cref="MemphisException"></exception> | ||
public static byte[] Serialize<T>(T obj, string schemaType) where T : class | ||
{ | ||
|
||
return schemaType switch | ||
{ | ||
MemphisSchemaTypes.JSON or | ||
MemphisSchemaTypes.GRAPH_QL => Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(obj)), | ||
MemphisSchemaTypes.PROTO_BUF => SerializeProtoBuf(obj), | ||
MemphisSchemaTypes.AVRO => AvroConvert.Serialize(obj), | ||
_ => throw new MemphisException("Unsupported schema type, the supported schema types are: json, graphql, protobuf, avro"), | ||
}; | ||
|
||
static byte[] SerializeProtoBuf<TData>(TData obj) where TData : class | ||
{ | ||
using var stream = new MemoryStream(); | ||
ProtoBuf.Serializer.Serialize(stream, obj); | ||
return stream.ToArray(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
using System.Threading.Tasks; | ||
using SolTechnology.Avro; | ||
|
||
using Memphis.Client.Exception; | ||
using System.Runtime.Serialization; | ||
using Newtonsoft.Json; | ||
|
||
namespace Memphis.Client.Validators; | ||
|
||
internal class AnotherUserModel | ||
{ | ||
[DataMember(Name = "name")] | ||
public string Name { get; set; } = null!; | ||
|
||
[DataMember(Name = "age")] | ||
public long Age { get; set; } | ||
} | ||
|
||
internal class AvroValidator : SchemaValidator<string>, ISchemaValidator | ||
{ | ||
public Task ValidateAsync(byte[] messageToValidate, string schemaKey) | ||
{ | ||
if (!_schemaCache.TryGetValue(schemaKey, out var schemaObj)) | ||
throw new MemphisSchemaValidationException($"Schema: {schemaKey} not found in local cache"); | ||
try | ||
{ | ||
_ = AvroConvert.Avro2Json(messageToValidate, schemaObj); | ||
return Task.CompletedTask; | ||
} | ||
catch (System.Exception exception) | ||
{ | ||
throw new MemphisSchemaValidationException($"Schema validation has failed: \n {exception.Message}", exception); | ||
} | ||
} | ||
|
||
protected override string Parse(string schemaData, string schemaName) | ||
{ | ||
try | ||
{ | ||
_ = AvroConvert.GenerateModel(schemaData); | ||
return schemaData; | ||
} | ||
catch (System.Exception exception) | ||
{ | ||
throw new MemphisException($"Schema parsing has failed: \n {exception.Message}", exception); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ internal enum ValidatorType | |
{ | ||
GRAPHQL = 1, | ||
JSON = 2, | ||
PROTOBUF = 3 | ||
PROTOBUF = 3, | ||
AVRO = 4 | ||
} | ||
} |