Skip to content

Commit

Permalink
Make time based values on JwtClaimsData (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
mtmk authored Aug 27, 2024
1 parent 9646d72 commit cf113d1
Show file tree
Hide file tree
Showing 14 changed files with 322 additions and 38 deletions.
167 changes: 158 additions & 9 deletions NATS.Jwt.Tests/Models/JwtClaimsDataTests.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Copyright (c) The NATS Authors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using NATS.Jwt.Internal;
using NATS.Jwt.Models;
using Xunit;

Expand All @@ -16,12 +19,12 @@ public void SerializeDeserialize_FullJwtClaimsData_ShouldSucceed()
{
Audience = "test_audience",
Id = "test_id",
IssuedAt = 1609459200, // 2021-01-01
IssuedAt = DateTimeOffset.FromUnixTimeSeconds(1609459200), // 2021-01-01
Issuer = "test_issuer",
Name = "Test JWT",
Subject = "test_subject",
Expires = 1735689600, // 2025-01-01
NotBefore = 1609459200, // 2021-01-01
Expires = DateTimeOffset.FromUnixTimeSeconds(1735689600), // 2025-01-01
NotBefore = DateTimeOffset.FromUnixTimeSeconds(1609459200), // 2021-01-01
};

string json = JsonSerializer.Serialize(claims);
Expand Down Expand Up @@ -53,10 +56,10 @@ public void SerializeDeserialize_MinimalJwtClaimsData_ShouldSucceed()
Assert.Equal(claims.Issuer, deserialized.Issuer);
Assert.Null(deserialized.Audience);
Assert.Null(deserialized.Id);
Assert.Equal(0, deserialized.IssuedAt);
Assert.Null(deserialized.IssuedAt);
Assert.Null(deserialized.Name);
Assert.Equal(0, deserialized.Expires);
Assert.Equal(0, deserialized.NotBefore);
Assert.Null(deserialized.Expires);
Assert.Null(deserialized.NotBefore);
}

[Fact]
Expand All @@ -76,10 +79,10 @@ public void Deserialize_ExtraFields_ShouldIgnore()
Assert.Equal("test_issuer", deserialized.Issuer);
Assert.Null(deserialized.Audience);
Assert.Null(deserialized.Id);
Assert.Equal(0, deserialized.IssuedAt);
Assert.Null(deserialized.IssuedAt);
Assert.Null(deserialized.Name);
Assert.Equal(0, deserialized.Expires);
Assert.Equal(0, deserialized.NotBefore);
Assert.Null(deserialized.Expires);
Assert.Null(deserialized.NotBefore);
}

[Fact]
Expand Down Expand Up @@ -110,4 +113,150 @@ public void Deserialize_InvalidJson_ShouldThrowException()

Assert.Throws<JsonException>(() => JsonSerializer.Deserialize<JwtClaimsData>(invalidJson));
}

[Fact]
public void Deserialize_WithNullValues_ShouldSetPropertiesToNull()
{
// Arrange
var json = "{}";

// Act
var claims = JsonSerializer.Deserialize<JwtClaimsData>(json);

// Assert
Assert.Null(claims.Audience);
Assert.Null(claims.Id);
Assert.Null(claims.IssuedAt);
Assert.Null(claims.Issuer);
Assert.Null(claims.Name);
Assert.Null(claims.Subject);
Assert.Null(claims.Expires);
Assert.Null(claims.NotBefore);
}

[Fact]
public void Serialize_WithNullValues_ShouldOmitNullProperties()
{
// Arrange
var claims = new JwtClaimsData();

// Act
var json = JsonSerializer.Serialize(claims);

// Assert
Assert.Equal("{}", json);
}

[Fact]
public void Deserialize_WithUnixTimestamps_ShouldConvertCorrectly()
{
// Arrange
var json = @"{
""iat"": 1609459200,
""exp"": 1609545600,
""nbf"": 1609372800
}";

// Act
var claims = JsonSerializer.Deserialize<JwtClaimsData>(json);

// Assert
Assert.Equal(new DateTimeOffset(2021, 1, 1, 0, 0, 0, TimeSpan.Zero), claims.IssuedAt);
Assert.Equal(new DateTimeOffset(2021, 1, 2, 0, 0, 0, TimeSpan.Zero), claims.Expires);
Assert.Equal(new DateTimeOffset(2020, 12, 31, 0, 0, 0, TimeSpan.Zero), claims.NotBefore);
}

[Fact]
public void NatsJsonDateTimeOffsetConverter_Read_ValidNumber_ShouldConvertCorrectly()
{
// Arrange
var json = @"{""Timestamp"": 1609459200}";
var options = new JsonSerializerOptions
{
Converters = { new NatsJsonDateTimeOffsetConverter() }
};

// Act
var result = JsonSerializer.Deserialize<TestClass>(json, options);

// Assert
Assert.Equal(new DateTimeOffset(2021, 1, 1, 0, 0, 0, TimeSpan.Zero), result.Timestamp);
}

[Fact]
public void NatsJsonDateTimeOffsetConverter_Read_NullValue_ShouldReturnNull()
{
// Arrange
var json = @"{""Timestamp"": null}";
var options = new JsonSerializerOptions
{
Converters = { new NatsJsonDateTimeOffsetConverter() }
};

// Act
var result = JsonSerializer.Deserialize<TestClass>(json, options);

// Assert
Assert.Null(result.Timestamp);
}

[Fact]
public void NatsJsonDateTimeOffsetConverter_Read_InvalidTokenType_ShouldThrowException()
{
// Arrange
var json = @"{""Timestamp"": ""not a number""}";
var options = new JsonSerializerOptions
{
Converters = { new NatsJsonDateTimeOffsetConverter() },
};

// Act & Assert
Assert.Throws<InvalidOperationException>(() => JsonSerializer.Deserialize<TestClass>(json, options));
}

[Fact]
public void NatsJsonDateTimeOffsetConverter_Write_ValidValue_ShouldWriteNumber()
{
// Arrange
var testObject = new TestClass
{
Timestamp = new DateTimeOffset(2021, 1, 1, 0, 0, 0, TimeSpan.Zero)
};
var options = new JsonSerializerOptions
{
Converters = { new NatsJsonDateTimeOffsetConverter() }
};

// Act
var json = JsonSerializer.Serialize(testObject, options);

// Assert
Assert.Equal(@"{""Timestamp"":1609459200}", json);
}

[Fact]
public void NatsJsonDateTimeOffsetConverter_Write_NullValue_ShouldWriteNull()
{
// Arrange
var testObject = new TestClass
{
Timestamp = null
};
var options = new JsonSerializerOptions
{
Converters = { new NatsJsonDateTimeOffsetConverter() }
};

// Act
var json = JsonSerializer.Serialize(testObject, options);

// Assert
Assert.Equal(@"{""Timestamp"":null}", json);
}

private class TestClass
{
[JsonConverter(typeof(NatsJsonDateTimeOffsetConverter))]
public DateTimeOffset? Timestamp { get; set; }
}
}
9 changes: 5 additions & 4 deletions NATS.Jwt.Tests/Models/NatsAccountClaimsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ public void SerializeDeserialize_FullNatsAccountClaims_ShouldSucceed()
Issuer = "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII",
Name = "Full Test Account",
Audience = "test_audience",
Expires = 1735689600, // 2025-01-01
IssuedAt = 1609459200, // 2021-01-01
NotBefore = 1609459200, // 2021-01-01
Expires = DateTimeOffset.FromUnixTimeSeconds(1735689600), // 2025-01-01
IssuedAt = DateTimeOffset.FromUnixTimeSeconds(1609459200), // 2021-01-01
NotBefore = DateTimeOffset.FromUnixTimeSeconds(1609459200), // 2021-01-01
Id = "jti_test",
Account = new NatsAccount
{
Expand Down Expand Up @@ -102,7 +102,8 @@ public void SerializeDeserialize_FullNatsAccountClaims_ShouldSucceed()
{
Pub = new NatsPermission
{
Allow = new List<string> { "allowed.>", }, Deny = new List<string> { "denied.>", },
Allow = new List<string> { "allowed.>", },
Deny = new List<string> { "denied.>", },
},
Sub =
new NatsPermission
Expand Down
7 changes: 4 additions & 3 deletions NATS.Jwt.Tests/Models/NatsActivationClaimsTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) The NATS Authors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Text.Json;
using NATS.Jwt.Models;
using Xunit;
Expand All @@ -18,9 +19,9 @@ public void SerializeDeserialize_FullNatsActivationClaims_ShouldSucceed()
Issuer = "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII",
Name = "Full Test Activation",
Audience = "test_audience",
Expires = 1735689600, // 2025-01-01
IssuedAt = 1609459200, // 2021-01-01
NotBefore = 1609459200, // 2021-01-01
Expires = DateTimeOffset.FromUnixTimeSeconds(1735689600), // 2025-01-01
IssuedAt = DateTimeOffset.FromUnixTimeSeconds(1609459200), // 2021-01-01
NotBefore = DateTimeOffset.FromUnixTimeSeconds(1609459200), // 2021-01-01
Id = "jti_test",
Activation = new NatsActivation
{
Expand Down
7 changes: 4 additions & 3 deletions NATS.Jwt.Tests/Models/NatsAuthorizationRequestClaimsTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) The NATS Authors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Collections.Generic;
using System.Text.Json;
using NATS.Jwt.Models;
Expand All @@ -19,9 +20,9 @@ public void SerializeDeserialize_FullNatsAuthorizationRequestClaims_ShouldSuccee
Issuer = "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII",
Name = "Full Test Authorization Request",
Audience = "test_audience",
Expires = 1735689600,
IssuedAt = 1609459200,
NotBefore = 1609459200,
Expires = DateTimeOffset.FromUnixTimeSeconds(1735689600),
IssuedAt = DateTimeOffset.FromUnixTimeSeconds(1609459200),
NotBefore = DateTimeOffset.FromUnixTimeSeconds(1609459200),
Id = "jti_test",
AuthorizationRequest = new NatsAuthorizationRequest
{
Expand Down
7 changes: 4 additions & 3 deletions NATS.Jwt.Tests/Models/NatsAuthorizationResponseClaimsTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) The NATS Authors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Text.Json;
using NATS.Jwt.Models;
using Xunit;
Expand All @@ -18,9 +19,9 @@ public void SerializeDeserialize_FullNatsAuthorizationResponseClaims_ShouldSucce
Issuer = "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII",
Name = "Full Test Authorization Response",
Audience = "test_audience",
Expires = 1735689600,
IssuedAt = 1609459200,
NotBefore = 1609459200,
Expires = DateTimeOffset.FromUnixTimeSeconds(1735689600),
IssuedAt = DateTimeOffset.FromUnixTimeSeconds(1609459200),
NotBefore = DateTimeOffset.FromUnixTimeSeconds(1609459200),
Id = "jti_test",
AuthorizationResponse = new NatsAuthorizationResponse
{
Expand Down
7 changes: 4 additions & 3 deletions NATS.Jwt.Tests/Models/NatsGenericFieldsClaimsTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) The NATS Authors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Text.Json;
using NATS.Jwt.Models;
using Xunit;
Expand All @@ -18,9 +19,9 @@ public void SerializeDeserialize_FullNatsGenericFieldsClaims_ShouldSucceed()
Issuer = "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII",
Name = "Full Test Generic Fields",
Audience = "test_audience",
Expires = 1735689600,
IssuedAt = 1609459200,
NotBefore = 1609459200,
Expires = DateTimeOffset.FromUnixTimeSeconds(1735689600),
IssuedAt = DateTimeOffset.FromUnixTimeSeconds(1609459200),
NotBefore = DateTimeOffset.FromUnixTimeSeconds(1609459200),
Id = "jti_test",
GenericFields = new NatsGenericFields
{
Expand Down
76 changes: 76 additions & 0 deletions NATS.Jwt.Tests/Models/NatsJsonDateTimeOffsetConverterTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) The NATS Authors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.IO;
using System.Text.Json;
using NATS.Jwt.Internal;
using Xunit;

namespace NATS.Jwt.Tests.Models;

public class NatsJsonDateTimeOffsetConverterTests
{
[Fact]
public void Read_UnsupportedType_ShouldThrowException()
{
// Act & Assert
var ex = Assert.Throws<InvalidOperationException>(() =>
{
// Arrange
var converter = new TestConverter();
var reader = new Utf8JsonReader(JsonSerializer.SerializeToUtf8Bytes(123));
reader.Read(); // Move to the first token
converter.Read(ref reader, typeof(DateTime), new JsonSerializerOptions());
});
Assert.Contains("Reading unknown date type", ex.Message);
}

[Fact]
public void Write_ValidValue_ShouldWriteCorrectly()
{
// Arrange
var converter = new TestConverter();
MemoryStream memoryStream = new();
var writer = new Utf8JsonWriter(memoryStream);
var value = new DateTimeOffset(2021, 1, 1, 0, 0, 0, TimeSpan.Zero);

// Act
converter.Write(writer, value, new JsonSerializerOptions());
writer.Flush();

// Assert
var json = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
Assert.Equal("1609459200", json);
}

[Fact]
public void Write_NullValue_ShouldWriteCorrectly()
{
// Arrange
var converter = new TestConverter();
MemoryStream memoryStream = new();
var writer = new Utf8JsonWriter(memoryStream);

// Act
converter.Write(writer, null, new JsonSerializerOptions());
writer.Flush();

// Assert
var json = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
Assert.Equal("null", json);
}

private class TestConverter : NatsJsonDateTimeOffsetConverter
{
public new void Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
base.Read(ref reader, typeToConvert, options);
}

public new void Write(Utf8JsonWriter writer, DateTimeOffset? value, JsonSerializerOptions options)
{
base.Write(writer, value, options);
}
}
}
Loading

0 comments on commit cf113d1

Please sign in to comment.