Skip to content

CBOR requests protocol test and extensions tests #3890

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

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
21 changes: 21 additions & 0 deletions extensions/AWSSDK.Extensions.sln
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AWSSDK.CommonTest", "..\sdk
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AWSSDK.S3.NetFramework", "..\sdk\src\Services\S3\AWSSDK.S3.NetFramework.csproj", "{1A313326-988F-4FF2-992E-6D7E50DCF598}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AWSSDK.Extensions.CborProtocol.NetFramework", "src\AWSSDK.Extensions.CborProtocol\AWSSDK.Extensions.CborProtocol.NetFramework.csproj", "{4FCCBD72-8E9B-D74B-6538-D8684D181230}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AWSSDK.Extensions.CborProtocol.NetStandard", "src\AWSSDK.Extensions.CborProtocol\AWSSDK.Extensions.CborProtocol.NetStandard.csproj", "{24CBBC97-409E-BAC8-0553-D260AB0B8C6A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CborProtocol.Tests.NetFramework", "test\CborProtocol.Tests\CborProtocol.Tests.NetFramework.csproj", "{9FFDECAB-94D6-7EB1-1A5B-487492600755}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -204,6 +210,18 @@ Global
{1A313326-988F-4FF2-992E-6D7E50DCF598}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A313326-988F-4FF2-992E-6D7E50DCF598}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A313326-988F-4FF2-992E-6D7E50DCF598}.Release|Any CPU.Build.0 = Release|Any CPU
{4FCCBD72-8E9B-D74B-6538-D8684D181230}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4FCCBD72-8E9B-D74B-6538-D8684D181230}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4FCCBD72-8E9B-D74B-6538-D8684D181230}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4FCCBD72-8E9B-D74B-6538-D8684D181230}.Release|Any CPU.Build.0 = Release|Any CPU
{24CBBC97-409E-BAC8-0553-D260AB0B8C6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{24CBBC97-409E-BAC8-0553-D260AB0B8C6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{24CBBC97-409E-BAC8-0553-D260AB0B8C6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{24CBBC97-409E-BAC8-0553-D260AB0B8C6A}.Release|Any CPU.Build.0 = Release|Any CPU
{9FFDECAB-94D6-7EB1-1A5B-487492600755}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9FFDECAB-94D6-7EB1-1A5B-487492600755}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9FFDECAB-94D6-7EB1-1A5B-487492600755}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9FFDECAB-94D6-7EB1-1A5B-487492600755}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -240,6 +258,9 @@ Global
{58BD3C7A-087C-4ECB-87C6-A3445025BEF5} = {A960D001-40B3-4B1A-A890-D1049FB7586E}
{AF5B5402-7C9A-4E5E-B0C2-9278BAE0435C} = {A960D001-40B3-4B1A-A890-D1049FB7586E}
{1A313326-988F-4FF2-992E-6D7E50DCF598} = {0BA39F07-84D6-420B-82D3-6DC3AF016C65}
{4FCCBD72-8E9B-D74B-6538-D8684D181230} = {3D822DC2-ED2E-4434-BC4F-CE7FCD846B02}
{24CBBC97-409E-BAC8-0553-D260AB0B8C6A} = {3D822DC2-ED2E-4434-BC4F-CE7FCD846B02}
{9FFDECAB-94D6-7EB1-1A5B-487492600755} = {A960D001-40B3-4B1A-A890-D1049FB7586E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {949367A4-5683-4FD3-93F4-A2CEA6EECB21}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472</TargetFrameworks>
<AssemblyName>CborProtocol.Tests</AssemblyName>
<PackageId>CborProtocol.Tests</PackageId>
<GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<LangVersion>Latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="../../../sdk/src/Core/AWSSDK.Core.NetFramework.csproj" />
<ProjectReference Include="../../src/AWSSDK.Extensions.CborProtocol/AWSSDK.Extensions.CborProtocol.NetFramework.csproj" />
</ItemGroup>
</Project>
45 changes: 45 additions & 0 deletions extensions/test/CborProtocol.Tests/WriteDateTimeTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using System.Formats.Cbor;
using Xunit;
using AWSSDK.Extensions.CborProtocol;

namespace Amazon.CborProtocol.Tests;

public class WriteDateTimeTests
{
[Theory]
[InlineData("1969-12-31T23:59:59Z", -1.0, CborReaderState.NegativeInteger, 2)]
[InlineData("1970-01-01T00:00:01Z", 1.0, CborReaderState.UnsignedInteger, 2)]
[InlineData("1970-01-01T00:00:00.500Z", 0.5, CborReaderState.SinglePrecisionFloat, 6)]
[InlineData("2025-01-01T00:00:00Z", 1735689600.0, CborReaderState.UnsignedInteger, 6)]
[InlineData("2025-06-19T20:15:28.468Z", 1750364128.468, CborReaderState.DoublePrecisionFloat, 10)]
public void WriteDateTime_EncodesCorrectly(string isoDate, double expectedUnixEpoch, CborReaderState expectedState, int expectedTotalBytes)
{
var dt = DateTime.Parse(isoDate);
var writer = new CborWriter();
writer.WriteDateTime(dt);

var encoded = writer.Encode();
var reader = new CborReader(encoded);
var tag = reader.ReadTag();

Assert.Equal(CborTag.UnixTimeSeconds, tag);
Assert.Equal(expectedState, reader.PeekState());

double value = 0;

if (expectedState == CborReaderState.SinglePrecisionFloat)
value = reader.ReadSingle();
else if (expectedState == CborReaderState.DoublePrecisionFloat)
value = reader.ReadDouble();
else if (expectedState == CborReaderState.UnsignedInteger)
value = reader.ReadUInt64();
else if (expectedState == CborReaderState.NegativeInteger)
value = reader.ReadInt64();
else
Assert.Fail($"CBOR state not found: ${reader.PeekState()}");

Assert.Equal(expectedUnixEpoch, value);
Assert.Equal(expectedTotalBytes, encoded.Length);
}
}
55 changes: 55 additions & 0 deletions extensions/test/CborProtocol.Tests/WriteOptimizedNumberTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System.Formats.Cbor;
using Xunit;
using AWSSDK.Extensions.CborProtocol;

namespace Amazon.CborProtocol.Tests;

public class WriteOptimizedNumberTests
{
[Theory]
[InlineData(0, 1)] // Fits in initial byte (major type + value)
[InlineData(23, 1)] // Still in initial byte
[InlineData(24, 2)] // One additional byte for UInt8
[InlineData(255, 2)] // UInt8
[InlineData(256, 3)] // UInt16
[InlineData(65535, 3)] // UInt16 max
[InlineData(65536, 5)] // UInt32
[InlineData(uint.MaxValue, 5)] // UInt32
[InlineData((long)uint.MaxValue + 1, 9)] // UInt64
public void WriteOptimizedNumber_UsesExpectedEncodingLength_ForUInt64(double value, int expectedBytes)
{
var writer = new CborWriter();
writer.WriteOptimizedNumber((double)value);
var encoded = writer.Encode();

Assert.Equal(expectedBytes, encoded.Length);
}

[Theory]
[InlineData(-1, 1)] // Negative integers encoded compactly
[InlineData(-24, 1)]
[InlineData(-25, 2)] // Beyond negative byte range
[InlineData(int.MinValue, 5)] // Should require full 32 bits
[InlineData(long.MinValue, 9)] // Full 64-bit negative integer
public void WriteOptimizedNumber_UsesExpectedEncodingLength_ForNegativeIntegers(long value, int expectedBytes)
{
var writer = new CborWriter();
writer.WriteOptimizedNumber((double)value);
var encoded = writer.Encode();

Assert.Equal(expectedBytes, encoded.Length);
}

[Theory]
[InlineData(1.5, 5, 0xFA)] // float32 marker + 4 bytes
[InlineData(123456789.12345, 9, 0xFB)] // Doesn't fit in float32
public void WriteOptimizedNumber_Float32_IsManuallyEncodedAsFiveBytes(double value, int expectedBytes, byte floatMarker)
{
var writer = new CborWriter();
writer.WriteOptimizedNumber(value);
var encoded = writer.Encode();

Assert.Equal(expectedBytes, encoded.Length);
Assert.Equal(floatMarker, encoded[0]); // Check float32 CBOR marker
}
}
10 changes: 10 additions & 0 deletions generator/.DevConfigs/6a90e4df-251e-45f8-808a-1a088cf0b25e.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

{
"core": {
"changeLogMessages": [
"Cbor protocol temp message"
],
"type": "patch",
"updateMinimum": true
}
}
5 changes: 3 additions & 2 deletions generator/ProtocolTestsGenerator/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ pluginManagement {
dependencyResolutionManagement {
versionCatalogs {
create("codegen") {
version("smithy", "1.54.0")
library("protocol-tests", "software.amazon.smithy", "smithy-aws-protocol-tests").versionRef("smithy")
version("smithy", "1.58.0")
library("protocol-tests", "software.amazon.smithy", "smithy-protocol-tests").versionRef("smithy")
library("protocol-aws-tests", "software.amazon.smithy", "smithy-aws-protocol-tests").versionRef("smithy")
library("codegen-core", "software.amazon.smithy", "smithy-codegen-core").versionRef("smithy")
library("protocol-tests-traits", "software.amazon.smithy", "smithy-protocol-test-traits").versionRef("smithy")
library("aws-traits", "software.amazon.smithy", "smithy-aws-traits").versionRef("smithy")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package software.amazon.smithy.dotnet.codegen;

import software.amazon.smithy.aws.traits.ServiceTrait;
import software.amazon.smithy.model.traits.TitleTrait;
import software.amazon.smithy.codegen.core.CodegenException;
import software.amazon.smithy.dotnet.codegen.utils.ProtocolTestUtils;
import software.amazon.smithy.model.Model;
Expand Down Expand Up @@ -51,7 +52,14 @@ public HttpProtocolTestGenerator(
this.model = context.model();
this.service = settings.getService(model);
this.context = context;
this.serviceNamespace = service.getTrait(ServiceTrait.class).get().getSdkId().replace(" ", "");

String serviceNamespace = null;
if (service.getTrait(ServiceTrait.class).isPresent())
serviceNamespace = service.getTrait(ServiceTrait.class).get().getSdkId();
else if (service.getTrait(TitleTrait.class).isPresent())
serviceNamespace = service.getTrait(TitleTrait.class).get().getValue().replace("Service", "");

this.serviceNamespace = serviceNamespace.replace(" ", "");
}

@Override
Expand All @@ -60,6 +68,8 @@ public void run() {
OperationIndex operationIndex = OperationIndex.of(model);
for (OperationShape operation : new TreeSet<>(topDownIndex.getContainedOperations(service))) {
var operationName = operation.getId().getName();
if (ProtocolTestCustomizations.OperationsToSkip.contains(operationName))
continue;
context.writerDelegator().useFileWriter(operationName + ".cs", serviceName, writer -> {
this.writer = writer;
addServiceProtocolSpecificImports();
Expand Down Expand Up @@ -87,14 +97,17 @@ private void addServiceProtocolSpecificImports() {
} else if (this.serviceName.toLowerCase().contains("xml")) {
writer.addImport(serviceName, "System.Xml");
writer.addImport(serviceName, "System.Xml.Linq");
} else if (this.serviceName.toLowerCase().contains("rpcv2")) {
writer.addImport(serviceName, "AWSSDK.Extensions.CborProtocol.Internal");
}
}

private void generateErrorResponseTests(OperationShape operation, OperationIndex index) {
for (StructureShape error : index.getErrors(operation, service)) {
error.getTrait(HttpResponseTestsTrait.class).ifPresent(trait -> {
for (HttpResponseTestCase httpResponseTestCase : trait.getTestCasesFor(AppliesTo.CLIENT)) {
generateErrorResponseTest(operation, error, httpResponseTestCase);
if (!trait.getTestCasesFor(AppliesTo.CLIENT).getFirst().getProtocol().getName().toLowerCase().contains("cbor")) // Skip CBOR response tests until the unmarshallers are ready
generateErrorResponseTest(operation, error, httpResponseTestCase);
}
});
}
Expand Down Expand Up @@ -283,6 +296,9 @@ private void assertRequestBody(HttpRequestTestCase httpRequestTestCase) {
} else if (httpRequestTestCase.getProtocol().getName().equals("restXml")) {
writer.write("var expectedBody = $S;", httpRequestTestCase.getBody());
writer.write("XmlTestUtils.AssertBody(marshalledRequest,expectedBody);");
} else if (this.marshallerType.equals("Cbor")) {
writer.write("var expectedBody = $S;", httpRequestTestCase.getBody());
writer.write("CborProtocolUtils.AssertBody(marshalledRequest, expectedBody);");
} else {
throw new CodegenException("Unsupported protocol detected while generating request test block.");
}
Expand All @@ -294,7 +310,8 @@ private void generateResponseTests(OperationShape operation) {
setMarshallerType(trait.getTestCasesFor(AppliesTo.CLIENT).getFirst().getProtocol().getName());
}
for (HttpResponseTestCase httpResponseTestCase : trait.getTestCasesFor(AppliesTo.CLIENT)) {
if (ProtocolTestCustomizations.TestsToSkip.contains(httpResponseTestCase.getId()) || httpResponseTestCase.hasTag("defaults"))
if (ProtocolTestCustomizations.TestsToSkip.contains(httpResponseTestCase.getId()) || httpResponseTestCase.hasTag("defaults")
|| trait.getTestCasesFor(AppliesTo.CLIENT).getFirst().getProtocol().getName().toLowerCase().contains("cbor")) // Skip CBOR response tests until the unmarshallers are ready
continue;
generateResponseTest(operation, httpResponseTestCase);
}
Expand Down Expand Up @@ -343,6 +360,8 @@ private void setMarshallerType(String protocol) {
this.marshallerType = "Json";
} else if (protocol.toLowerCase().contains("xml") || protocol.toLowerCase().contains("query")) {
this.marshallerType = "Xml";
} else if (protocol.toLowerCase().contains("cbor")) {
this.marshallerType = "Cbor";
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ private ProtocolTestCustomizations() {
"SparseBooleanMap",
"SparseNumberMap"
);

// These operations don't exist in C2J
public static final List<String> OperationsToSkip = Arrays.asList(
"RpcV2CborSparseMaps",
"OperationWithDefaults",
"SparseNullsOperation"
);

//The rename is written in smithy and since we're generating from the C2J structures we will skip this test.
public static final List<String> TestsToSkip = Arrays.asList(
"RestJsonSerializeRenamedStructureUnionValue",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ repositories {

dependencies {
implementation(project(":smithy-dotnet-codegen"))
implementation(codegen.protocol.aws.tests)
implementation(codegen.protocol.tests)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,24 @@
"packageVersion": "0.0.1"
}
}
},
"RpcV2Protocol": {
"transforms": [
{
"name": "includeServices",
"args": {
"services": [
"smithy.protocoltests.rpcv2Cbor#RpcV2Protocol"
]
}
}
],
"plugins": {
"dotnet-protocol-test-codegen": {
"service": "smithy.protocoltests.rpcv2Cbor#RpcV2Protocol",
"packageVersion": "0.0.1"
}
}
}
}
}
Loading