Skip to content

Commit

Permalink
ProtoBuf eval update (#118)
Browse files Browse the repository at this point in the history
* Updated ProtoBuf descriptor to base64, and added unit tests
  • Loading branch information
tbazen authored Aug 7, 2023
1 parent 5a8bbb3 commit b27153b
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 38 deletions.
3 changes: 2 additions & 1 deletion src/Memphis.Client/Validators/ProtoBufValidator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Text;
using System.Threading.Tasks;
using Memphis.Client.Exception;

Expand Down Expand Up @@ -29,7 +30,7 @@ public async Task ValidateAsync(byte[] messageToValidate, string schemaAsStr)
{
var result = await ProtoBufEval.ProtoBufValidator.Validate(
base64Data: Convert.ToBase64String(messageToValidate),
activeSchemaVersion: protoBufSchema.ActiveSchemaVersion,
activeSchemaVersion: Convert.ToBase64String(Encoding.UTF8.GetBytes(protoBufSchema.ActiveSchemaVersion)),
schemaName: protoBufSchema.SchemaName);
if(result.HasError)
throw new MemphisSchemaValidationException($"Schema validation has failed: \n {result.Error}");
Expand Down
110 changes: 82 additions & 28 deletions src/ProtoBufEval.Tests/ProtoBufValidatorTests.cs
Original file line number Diff line number Diff line change
@@ -1,48 +1,102 @@
using ProtoBuf;
using System.Text;

namespace ProtoBufEval.Tests;



[ProtoContract]
public class Test
{

[ProtoMember(1, Name = @"field1")]
[global::System.ComponentModel.DefaultValue("")]
public string Field1 { get; set; } = "";

[ProtoMember(2, Name = @"field2")]
[System.ComponentModel.DefaultValue("")]
public string Field2 { get; set; } = "";

[ProtoMember(3, Name = @"field3")]
public int Field3 { get; set; }

}


[ProtoContract]
public class InvalidTestModel
{

[ProtoMember(1, Name = @"field1")]
[global::System.ComponentModel.DefaultValue("")]
public string Field1 { get; set; } = "";

[ProtoMember(3, Name = @"field3")]
public int Field3 { get; set; }

}

public class ProtoBufValidatorTests
{
// [Theory]
// [InlineData(
// "c3lzdGVtID0gInByb3RvMyI7CgpkYXRhYmFzZSBleGFtcGxlOwpfbWFpbk1lc3NhZ2UgUGVyc29uIHsKICBuYW1lID0gMTsKICBpbnQzMiBhZ2UgPSAyOwoKICBzdHJpbmcgZW1haWwgPSAzOwp9Cg==",
// """
// {
// "version_number": 1,
// "descriptor": "\nf\n\u000cprt2_1.proto\"N\n\u0004Test\u0012\u0016\n\u0006field1\u0018\u0001 \u0001(\tR\u0006field1\u0012\u0016\n\u0006field2\u0018\u0002 \u0001(\tR\u0006field2\u0012\u0016\n\u0006field3\u0018\u0003 \u0001(\u0005R\u0006field3b\u0006proto3",
// "schema_content": "syntax = \"proto3\";\nmessage Test {\n string field1 = 1;\n string field2 = 2;\n int32 field3 = 3;\n}",
// "message_struct_name": "Test"
// }
// """,
// "prt2"
// )]
// public async Task GivenValidPayload_WhenValidate_ThenNoError(string base64Data, string activeSchemaVersion, string schemaName)
// {
// var result = await ProtoBufValidator.Validate(base64Data, activeSchemaVersion, schemaName);


// Assert.False(result.HasError);
// Assert.Null(result.Error);
// }
[Theory]
[InlineData(
"""
{
"version_number": 1,
"descriptor": "CmsKEXNhbXBsZXBiZl8xLnByb3RvIk4KBFRlc3QSFgoGZmllbGQxGAEgASgJUgZmaWVsZDESFgoGZmllbGQyGAIgASgJUgZmaWVsZDISFgoGZmllbGQzGAMgASgFUgZmaWVsZDNiBnByb3RvMw==",
"schema_content": "syntax = \"proto3\";\nmessage Test {\n string field1 = 1;\n string field2 = 2;\n int32 field3 = 3;\n}",
"message_struct_name": "Test"
}
""",
"samplepbf"
)]
public async Task GivenValidPayload_WhenValidate_ThenNoError(string activeSchemaVersion, string schemaName)
{
var validData = new Test
{
Field1 = "AwesomeFirst",
Field2 = "SecondField",
Field3 = 333,
};
var base64ValidData = ConvertProtoBufToBase64(validData);
var activeSchemaVersionBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(activeSchemaVersion));

var result = await ProtoBufValidator.Validate(base64ValidData, activeSchemaVersionBase64, schemaName);

Assert.False(result.HasError);
Assert.Null(result.Error);
}

[Theory]
[InlineData(
"c3lzdGVtID0gInByb3RvMyI7CgpkYXRhYmFzZSBleGFtcGxlOwpfbWFpbk1lc3NhZ2UgUGVyc29uIHsKICBuYW1lID0gMTsKICBpbnQzMiBhZ2UgPSAyOwoKICBzdHJpbmcgZW1haWwgPSAzOwp9Cg==",
"""
{
"version_number": 1,
"descriptor": "\nf\n\u000cprt2_1.proto\"N\n\u0004Test\u0012\u0016\n\u0006field1\u0018\u0001 \u0001(\tR\u0006field1\u0012\u0016\n\u0006field2\u0018\u0002 \u0001(\tR\u0006field2\u0012\u0016\n\u0006field3\u0018\u0003 \u0001(\u0005R\u0006field3b\u0006proto3",
"schema_content": "syntax = \"proto3\";\nmessage Test {\n string field1 = 1;\n string field2 = 2;\n int32 field3 = 3;\n}",
"version_number": 1,
"descriptor": "CmsKEXNhbXBsZXBiZl8xLnByb3RvIk4KBFRlc3QSFgoGZmllbGQxGAEgASgJUgZmaWVsZDESFgoGZmllbGQyGAIgASgJUgZmaWVsZDISFgoGZmllbGQzGAMgASgFUgZmaWVsZDNiBnByb3RvMw==",
"schema_content": "syntax = \"proto3\";\nmessage Test {\n string field1 = 1;\n string field2 = 2;\n int32 field3 = 3;\n}",
"message_struct_name": "Test"
}
""",
"prt2"
"samplepbf"
)]
public async Task GivenInvalidPayload_WhenValidate_ThenHasError(string base64Data, string activeSchemaVersion, string schemaName)
public async Task GivenInvalidPayload_WhenValidate_ThenHasError(string activeSchemaVersion, string schemaName)
{
var result = await ProtoBufValidator.Validate(base64Data, activeSchemaVersion, schemaName);
var base64InvalidData = Convert.ToBase64String(Encoding.UTF8.GetBytes("CgJmb3JtYWwxCgRmZWlsZDIKCAk="));
var activeSchemaVersionBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(activeSchemaVersion));

var result = await ProtoBufValidator.Validate(base64InvalidData, activeSchemaVersionBase64, schemaName);


Assert.True(result.HasError);
Assert.NotNull(result.Error);
}



private static string ConvertProtoBufToBase64<TData>(TData obj) where TData : class
{
using var stream = new MemoryStream();
ProtoBuf.Serializer.Serialize(stream, obj);
return Convert.ToBase64String(stream.ToArray());
}
}
6 changes: 3 additions & 3 deletions src/ProtoBufEval/ProtoBufValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@ static ProtoBufValidator()
/// Validate a base64 encoded protobuf payload against a schema
/// </summary>
/// <param name="base64Data"></param>
/// <param name="activeSchemaVersion"></param>
/// <param name="activeSchemaVersionBase64"></param>
/// <param name="schemaName"></param>
/// <returns></returns>
public static async Task<ProtoBufValidationResult> Validate(string base64Data, string activeSchemaVersion, string schemaName)
public static async Task<ProtoBufValidationResult> Validate(string base64Data, string activeSchemaVersionBase64, string schemaName)
{
var result = await Cli.Wrap(_nativeBinary)
.WithArguments(new[] {
"eval",
"--payload",base64Data,
"--schema", activeSchemaVersion,
"--schema", activeSchemaVersionBase64,
"--schema-name", schemaName
})
.WithValidation(CommandResultValidation.None)
Expand Down
19 changes: 13 additions & 6 deletions src/protoeval-cli/cmd/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ func init() {
type any interface{}

type SchemaVersion struct {
VersionNumber int `json:"version_number"`
VersionNumber int `json:"version_number"`
// Descriptor is a base64 encoded FileDescriptorSet
Descriptor string `json:"descriptor"`
Content string `json:"schema_content"`
MessageStructName string `json:"message_struct_name"`
Expand All @@ -72,9 +73,13 @@ func handleProtoBufEval(context context.Context) {
}
}

func unmarshalSchemaVersion(data string) (SchemaVersion, error) {
func unmarshalSchemaVersion(base64SchemaVersion string) (SchemaVersion, error) {
var schemaVersion SchemaVersion
err := json.Unmarshal([]byte(data), &schemaVersion)
bytes, err := base64.StdEncoding.DecodeString(base64SchemaVersion)
if err != nil {
return schemaVersion, protoevalError(err)
}
err = json.Unmarshal(bytes, &schemaVersion)
if err != nil {
return schemaVersion, protoevalError(err)
}
Expand All @@ -83,9 +88,11 @@ func unmarshalSchemaVersion(data string) (SchemaVersion, error) {

func compileDescriptor(activeVersion SchemaVersion, schemaName string) (protoreflect.MessageDescriptor, error) {
descriptorSet := descriptorpb.FileDescriptorSet{}
fmt.Println(activeVersion.Descriptor)
fmt.Println([]byte(activeVersion.Descriptor))
err := proto.Unmarshal([]byte(activeVersion.Descriptor), &descriptorSet)
descriptorBytes, err := base64.StdEncoding.DecodeString(activeVersion.Descriptor)
if err != nil {
return nil, protoevalError(err)
}
err = proto.Unmarshal(descriptorBytes, &descriptorSet)
if err != nil {
return nil, protoevalError(err)
}
Expand Down

0 comments on commit b27153b

Please sign in to comment.