Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: make optional properties of bindings nullable #89

Merged
merged 25 commits into from
Mar 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
366a2f3
Make optional fields in the Pulsar binding nullable
ullebe1 Feb 7, 2023
8acd340
Make optional field in the Kafka binding nullable
ullebe1 Feb 7, 2023
37daddb
Make optional fields in the HTTP binding nullable
ullebe1 Feb 7, 2023
b503883
Make optional fields in the Websockets binding nullable
ullebe1 Feb 7, 2023
438d2ee
AsyncApiReference is already nullable
ullebe1 Feb 9, 2023
ef0e8a0
TopicConfigurationObject is WriteOptional
ullebe1 Feb 9, 2023
ea5f862
IEnumerable is already nullable
ullebe1 Feb 9, 2023
9b3f44a
RetentionDefinition is WriteOptional
ullebe1 Feb 9, 2023
f32ba66
String is already nullable, and we will be setting a default instead …
ullebe1 Feb 9, 2023
5afa4ef
Add GetScalarValueOrDefault(string defaultValue)
ullebe1 Feb 9, 2023
6eb7278
Parse bindingVersion with a default of "latest" for all bindings
ullebe1 Feb 9, 2023
80e7258
Revert accidental bumping of target framework
ullebe1 Feb 9, 2023
97abe32
add OrDefault versions of scalar value fetching
VisualBean Feb 14, 2023
9eed15c
retract "Default" reading of binding version
VisualBean Feb 14, 2023
9c6d5aa
Bump AsyncApi version
ullebe1 Feb 22, 2023
cf37e51
Put versions in quotes as they're strings per the spec
ullebe1 Feb 22, 2023
973ba60
Add default null tests for Pulsar server bindings
ullebe1 Feb 22, 2023
0ec6026
Add default value tests for Pulsar Bindings
ullebe1 Feb 22, 2023
b936835
Remove "Nullable" from csproj
ullebe1 Feb 27, 2023
b7e0caa
Remove ? from types that are already nullable
ullebe1 Feb 27, 2023
c360285
Revert "Put versions in quotes as they're strings per the spec"
ullebe1 Feb 28, 2023
e6b623a
Since Persistence is an Enum it has to be explicitly nullable or it d…
ullebe1 Feb 28, 2023
acb6913
Merge branch 'main' into ullebe1/optionals_nullable
VisualBean Feb 28, 2023
669017b
Use a shared reference to the binding in the test, rather than findin…
ullebe1 Feb 28, 2023
ff004f8
Merge remote-tracking branch 'origin/ullebe1/optionals_nullable' into…
ullebe1 Feb 28, 2023
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
20 changes: 20 additions & 0 deletions src/LEGO.AsyncAPI.Readers/ParseNodes/ParseNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,21 +94,41 @@ public virtual string GetScalarValue()
throw new AsyncApiReaderException("Cannot create a scalar value from this type of node.", this.Context);
}

public virtual string GetScalarValueOrDefault(string defaultValue)
{
throw new AsyncApiReaderException("Cannot create a scalar value from this type of node.", this.Context);
}

public virtual bool GetBooleanValue()
{
throw new AsyncApiReaderException("Cannot create a scalar value from this type of node.", this.Context);
}

public virtual bool? GetBooleanValueOrDefault(bool? defaultValue)
{
throw new AsyncApiReaderException("Cannot create a scalar value from this type of node.", this.Context);
}

public virtual int GetIntegerValue()
{
throw new AsyncApiReaderException("Cannot create a scalar value from this type of node.", this.Context);
}

public virtual int? GetIntegerValueOrDefault(int? defaultValue)
{
throw new AsyncApiReaderException("Cannot create a scalar value from this type of node.", this.Context);
}

public virtual long GetLongValue()
{
throw new AsyncApiReaderException("Cannot create a scalar value from this type of node.", this.Context);
}

public virtual long? GetLongValueOrDefault(long? defaultValue)
{
throw new AsyncApiReaderException("Cannot create a scalar value from this type of node.", this.Context);
}

public virtual List<IAsyncApiAny> CreateListOfAny()
{
throw new AsyncApiReaderException("Cannot create a list from this type of node.", this.Context);
Expand Down
40 changes: 40 additions & 0 deletions src/LEGO.AsyncAPI.Readers/ParseNodes/ValueNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ public override string GetScalarValue()
return this.node.Value;
}

public override string GetScalarValueOrDefault(string defaultValue)
{
if (this.node.Value is not null)
{
return this.node.Value;
}

return defaultValue;
}

public override int GetIntegerValue()
{
if (int.TryParse(this.node.Value, out int value))
Expand All @@ -39,6 +49,16 @@ public override int GetIntegerValue()
throw new AsyncApiReaderException("Value could not parse to integer", this.node);
}

public override int? GetIntegerValueOrDefault(int? defaultValue)
{
if (int.TryParse(this.node.Value, out int value))
{
return value;
}

return defaultValue;
}

public override long GetLongValue()
{
if (long.TryParse(this.node.Value, out long value))
Expand All @@ -49,6 +69,16 @@ public override long GetLongValue()
throw new AsyncApiReaderException("Value could not parse to long", this.node);
}

public override long? GetLongValueOrDefault(long? defaultValue)
{
if (long.TryParse(this.node.Value, out long value))
{
return value;
}

return defaultValue;
}

public override bool GetBooleanValue()
{
if (bool.TryParse(this.node.Value, out bool value))
Expand All @@ -59,6 +89,16 @@ public override bool GetBooleanValue()
throw new AsyncApiReaderException("Value could not parse to bool", this.node);
}

public override bool? GetBooleanValueOrDefault(bool? defaultValue)
{
if (bool.TryParse(this.node.Value, out bool value))
{
return value;
}

return defaultValue;
}

public override IAsyncApiAny CreateAny()
{
var value = this.GetScalarValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ public class KafkaChannelBinding : IChannelBinding
/// <summary>
/// Number of partitions configured on this topic (useful to know how many parallel consumers you may run).
/// </summary>
public int Partitions { get; set; }
public int? Partitions { get; set; }

/// <summary>
/// Number of replicas configured on this topic.
/// </summary>
public int Replicas { get; set; }
public int? Replicas { get; set; }

/// <summary>
/// Topic configuration properties that are relevant for the API.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,22 @@ public class TopicConfigurationObject : IAsyncApiElement
/// <summary>
/// The retention.ms configuration option.
/// </summary>
public int RetentionMiliseconds { get; set; }
public int? RetentionMiliseconds { get; set; }

/// <summary>
/// The retention.bytes configuration option.
/// </summary>
public int RetentionBytes { get; set; }
public int? RetentionBytes { get; set; }

/// <summary>
/// The delete.retention.ms configuration option.
/// </summary>
public int DeleteRetentionMiliseconds { get; set; }
public int? DeleteRetentionMiliseconds { get; set; }

/// <summary>
/// The max.message.bytes configuration option.
/// </summary>
public int MaxMessageBytes { get; set; }
public int? MaxMessageBytes { get; set; }

public void Serialize(IAsyncApiWriter writer)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ public class PulsarChannelBinding : IChannelBinding
/// <summary>
/// persistence of the topic in Pulsar persistent or non-persistent.
/// </summary>
public Persistence Persistence { get; set; }
public Persistence? Persistence { get; set; }

/// <summary>
/// Topic compaction threshold given in bytes.
/// </summary>
public int Compaction { get; set; }
public int? Compaction { get; set; }

/// <summary>
/// A list of clusters the topic is replicated to.
Expand All @@ -40,12 +40,12 @@ public class PulsarChannelBinding : IChannelBinding
/// <summary>
/// Message Time-to-live in seconds.
/// </summary>
public int TTL { get; set; }
public int? TTL { get; set; }

/// <summary>
/// When Message deduplication is enabled, it ensures that each message produced on Pulsar topics is persisted to disk only once.
/// </summary>
public bool Deduplication { get; set; }
public bool? Deduplication { get; set; }

/// <summary>
/// The version of this binding.
Expand Down
114 changes: 113 additions & 1 deletion test/LEGO.AsyncAPI.Tests/Bindings/Pulsar/PulsarBindings_Should.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace LEGO.AsyncAPI.Tests.Bindings.Pulsar
using LEGO.AsyncAPI.Models.Bindings;

namespace LEGO.AsyncAPI.Tests.Bindings.Pulsar
{
using FluentAssertions;
using LEGO.AsyncAPI.Models;
Expand Down Expand Up @@ -64,6 +66,44 @@ public void PulsarChannelBinding_WithFilledObject_SerializesAndDeserializes()
binding.Should().BeEquivalentTo(channel);
}

[Test]
public void PulsarChannelBindingNamespaceDefaultToNull()
{
// Arrange
var actual =
@"bindings:
pulsar:
persistence: persistent";

// Act
// Assert
var binding = new AsyncApiStringReader().ReadFragment<AsyncApiChannel>(actual, AsyncApiVersion.AsyncApi2_0, out _);

Assert.AreEqual(null, ((PulsarChannelBinding)binding.Bindings[BindingType.Pulsar]).Namespace);
}

[Test]
public void PulsarChannelBindingPropertiesExceptNamespaceDefaultToNull()
{
// Arrange
var actual =
@"bindings:
pulsar:
namespace: staging";

// Act
// Assert
var binding = new AsyncApiStringReader().ReadFragment<AsyncApiChannel>(actual, AsyncApiVersion.AsyncApi2_0, out _);
var pulsarBinding = ((PulsarChannelBinding) binding.Bindings[BindingType.Pulsar]);

Assert.AreEqual(null, pulsarBinding.Persistence);
Assert.AreEqual(null, pulsarBinding.Compaction);
Assert.AreEqual(null, pulsarBinding.GeoReplication);
Assert.AreEqual(null, pulsarBinding.Retention);
Assert.AreEqual(null, pulsarBinding.TTL);
Assert.AreEqual(null, pulsarBinding.Deduplication);
}

[Test]
public void PulsarServerBinding_WithFilledObject_SerializesAndDeserializes()
{
Expand Down Expand Up @@ -97,5 +137,77 @@ public void PulsarServerBinding_WithFilledObject_SerializesAndDeserializes()
Assert.AreEqual(actual, expected);
binding.Should().BeEquivalentTo(server);
}

[Test]
public void ServerBindingVersionDefaultsToNull()
{
// Arrange
var expected =
@"url: https://example.com
protocol: pulsar
bindings:
pulsar:
tenant: contoso";

var server = new AsyncApiServer()
{
Url = "https://example.com",
Protocol = "pulsar",
};

server.Bindings.Add(new PulsarServerBinding
{
Tenant = "contoso",
BindingVersion = null,
});

// Act
var actual = server.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0);
actual = actual.MakeLineBreaksEnvironmentNeutral();
expected = expected.MakeLineBreaksEnvironmentNeutral();

var binding = new AsyncApiStringReader().ReadFragment<AsyncApiServer>(actual, AsyncApiVersion.AsyncApi2_0, out _);

// Assert
Assert.AreEqual(actual, expected);
Assert.AreEqual(null, ((PulsarServerBinding)binding.Bindings[BindingType.Pulsar]).BindingVersion);
binding.Should().BeEquivalentTo(server);
}

[Test]
public void ServerTenantDefaultsToNull()
{
// Arrange
var expected =
@"url: https://example.com
protocol: pulsar
bindings:
pulsar:
bindingVersion: latest";

var server = new AsyncApiServer()
{
Url = "https://example.com",
Protocol = "pulsar",
};

server.Bindings.Add(new PulsarServerBinding
{
Tenant = null,
BindingVersion = "latest",
});

// Act
var actual = server.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0);
actual = actual.MakeLineBreaksEnvironmentNeutral();
expected = expected.MakeLineBreaksEnvironmentNeutral();

var binding = new AsyncApiStringReader().ReadFragment<AsyncApiServer>(actual, AsyncApiVersion.AsyncApi2_0, out _);

// Assert
Assert.AreEqual(actual, expected);
Assert.AreEqual(null, ((PulsarServerBinding)binding.Bindings[BindingType.Pulsar]).Tenant);
binding.Should().BeEquivalentTo(server);
}
}
}
4 changes: 2 additions & 2 deletions test/LEGO.AsyncAPI.Tests/Models/AsyncApiMessage_Should.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,10 @@ public void AsyncApiMessage_WithSchemaFormat_Serializes()
type:
- string
- 'null'
schemaFormat: application/vnd.aai.asyncapi+json;version=2.5.0";
schemaFormat: application/vnd.aai.asyncapi+json;version=2.6.0";

var message = new AsyncApiMessage();
message.SchemaFormat = "application/vnd.aai.asyncapi+json;version=2.5.0";
message.SchemaFormat = "application/vnd.aai.asyncapi+json;version=2.6.0";
message.Payload = new AsyncApiSchema()
{
Properties = new Dictionary<string, AsyncApiSchema>()
Expand Down