diff --git a/generator/ServiceClientGeneratorLib/Generators/TestFiles/SmokeTestsV2.partial.cs b/generator/ServiceClientGeneratorLib/Generators/TestFiles/SmokeTestsV2.partial.cs index 2753fbf64471..0980c1702722 100644 --- a/generator/ServiceClientGeneratorLib/Generators/TestFiles/SmokeTestsV2.partial.cs +++ b/generator/ServiceClientGeneratorLib/Generators/TestFiles/SmokeTestsV2.partial.cs @@ -8,6 +8,7 @@ namespace ServiceClientGenerator.Generators.TestFiles { public partial class SmokeTestsV2 { + #region Core Configuration Properties public string GetRegion(JsonData testCase) { var config = testCase["config"]; @@ -21,17 +22,183 @@ public string GetRegion(JsonData testCase) return region.ToJson(); } + public string GetUri(JsonData testCase) + { + var config = testCase["config"]; + if (config == null) + return null; + + var uri = config["uri"]; + if (uri == null) + return null; + + return $"\"{uri.ToString()}\""; + } + + #endregion + + #region Endpoint Configuration Properties + public bool? GetUseFipsEndpoint(JsonData testCase) + { + var config = testCase["config"]; + if (config == null) + return null; + + var useFips = config["useFips"]; + if (useFips == null) + return null; + + return (bool)useFips; + } + + public bool? GetUseDualstackEndpoint(JsonData testCase) + { + var config = testCase["config"]; + if (config == null) + return null; + + var useDualstack = config["useDualstack"]; + if (useDualstack == null) + return null; + + return (bool)useDualstack; + } + #endregion + + #region S3-Specific Configuration Properties + public bool? GetUseAccelerateEndpoint(JsonData testCase) + { + var config = testCase["config"]; + if (config == null) + return null; + + var useAccelerate = config["useAccelerate"]; + if (useAccelerate == null) + return null; + + return (bool)useAccelerate; + } + + public bool? GetUseGlobalEndpoint(JsonData testCase) + { + var config = testCase["config"]; + if (config == null) + return null; + + var useGlobalEndpoint = config["useGlobalEndpoint"]; + if (useGlobalEndpoint == null) + return null; + + return (bool)useGlobalEndpoint; + } + + public bool? GetUseArnRegion(JsonData testCase) + { + var config = testCase["config"]; + if (config == null) + return null; + + var useArnRegion = config["useArnRegion"]; + if (useArnRegion == null) + return null; + + return (bool)useArnRegion; + } + + public bool? GetForcePathStyle(JsonData testCase) + { + var config = testCase["config"]; + if (config == null) + return null; + + var forcePathStyle = config["forcePathStyle"]; + if (forcePathStyle == null) + return null; + + return (bool)forcePathStyle; + } + #endregion + + #region Authentication Configuration Properties + public bool? GetUseAccountIdRouting(JsonData testCase) + { + var config = testCase["config"]; + if (config == null) + return null; + + var useAccountIdRouting = config["useAccountIdRouting"]; + if (useAccountIdRouting == null) + return null; + + return (bool)useAccountIdRouting; + } + + public string[] GetSigV4aRegionSet(JsonData testCase) + { + var config = testCase["config"]; + if (config == null) + return null; + + var sigv4aRegionSet = config["sigv4aRegionSet"]; + if (sigv4aRegionSet == null || !sigv4aRegionSet.IsArray) + return null; + + var regions = new List(); + foreach (JsonData region in sigv4aRegionSet) + { + regions.Add(region.ToString()); + } + return regions.ToArray(); + } + #endregion + + #region Test Case Properties + public JsonData GetInput(JsonData testCase) + { + return testCase["input"]; + } + + public bool IsSuccessExpected(JsonData testCase) + { + var expectation = testCase["expectation"]; + return expectation["success"] != null; + } + + public string GetExpectedErrorId(JsonData testCase) + { + var expectation = testCase["expectation"]; + var failure = expectation["failure"]; + return failure?["errorId"]?.ToString(); + } + #endregion + /// /// Finds the operation in the ServiceModel based on the operation name in the smoke2 json file. The /// name in that file does not take any customizations that might have been put in place. So we need to /// compare to the raw ShapeName instead of Name property which has customizations applied. /// - /// - /// private Operation FindOperation(JsonData testCase) { var operationShapeName = testCase["operationName"].ToString(); return this.Config.ServiceModel.Operations.FirstOrDefault(x => string.Equals(x.ShapeName, operationShapeName)); } + + /// + /// Finds the proper .NET property name for a given JSON key in the operation's input shape. + /// + private string FindPropertyName(Operation operation, string jsonKey) + { + // Get the input shape for the operation + var inputShape = operation.RequestStructure; + if (inputShape == null) + return jsonKey; + + // Look for a member in the input shape that matches the json key + var member = inputShape.Members.FirstOrDefault(m => + string.Equals(m.MarshallLocationName, jsonKey, StringComparison.OrdinalIgnoreCase)); + + // If found, return the .NET customized name, otherwise return original key + return member?.PropertyName ?? jsonKey; + } } } \ No newline at end of file diff --git a/generator/ServiceClientGeneratorLib/Generators/TestFiles/SmokeTestsV2.tt b/generator/ServiceClientGeneratorLib/Generators/TestFiles/SmokeTestsV2.tt index d19757f11378..bc09eb016de3 100644 --- a/generator/ServiceClientGeneratorLib/Generators/TestFiles/SmokeTestsV2.tt +++ b/generator/ServiceClientGeneratorLib/Generators/TestFiles/SmokeTestsV2.tt @@ -8,6 +8,7 @@ AddLicenseHeader(); #> using System; +using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -26,36 +27,283 @@ namespace AWSSDK_DotNet.IntegrationTests.SmokeTestsV2 var modeledOperation = FindOperation(testCase); if (modeledOperation == null) throw new ApplicationException($"Failed to find operation {testCase["operationName"]} for {testCase["id"]} while generating smoke tests for service {this.Config.ServiceModel.ServiceId}"); + + var testTags = testCase["tags"] as JsonData; #> [TestMethod] [TestCategory("SmokeTests")] [TestCategory("<#=this.Config.ServiceModel.ServiceId#>")] - public async Task <#=testCase["id"].ToString()#>() +<# + if (testTags != null && testTags.IsArray) + { + foreach (JsonData tag in testTags) + { + var tagValue = tag?.ToString(); + if (!string.IsNullOrEmpty(tagValue)) + { +#> + [TestCategory("<#=tagValue#>")] +<# + } + } + } +#> + public async Task <#=testCase["id"]#>() { var serviceConfig = new Amazon<#=this.Config.ClassName#>Config(); - - // TODO: Apply any other config settings required for the service config. <# - if (this.GetRegion(testCase) != null) - { + var region = this.GetRegion(testCase); + if (!string.IsNullOrEmpty(region)) + { +#> + serviceConfig.RegionEndpoint = RegionEndpoint.GetBySystemName(<#=region#>); +<# + } + if (this.GetUseFipsEndpoint(testCase) != null && (bool)this.GetUseFipsEndpoint(testCase)) + { +#> + serviceConfig.UseFIPSEndpoint = true; +<# + } + if (this.GetUseDualstackEndpoint(testCase) != null && (bool)this.GetUseDualstackEndpoint(testCase)) + { +#> + serviceConfig.UseDualstackEndpoint = true; +<# + } + var uri = this.GetUri(testCase); + if (!string.IsNullOrEmpty(uri)) + { +#> + serviceConfig.ServiceURL = <#=uri#>; +<# + } + if (this.GetUseAccelerateEndpoint(testCase) != null) + { +#> + serviceConfig.UseAccelerateEndpoint = <#=this.GetUseAccelerateEndpoint(testCase).ToString().ToLower()#>; +<# + } + if (this.GetUseGlobalEndpoint(testCase) != null) + { +#> + serviceConfig.UseGlobalEndpoint = <#=this.GetUseGlobalEndpoint(testCase).ToString().ToLower()#>; +<# + } + if (this.GetUseArnRegion(testCase) != null) + { #> - serviceConfig.RegionEndpoint = RegionEndpoint.GetBySystemName(<#=this.GetRegion(testCase)#>); + serviceConfig.UseArnRegion = <#=this.GetUseArnRegion(testCase).ToString().ToLower()#>; <# - } + } + if (this.GetForcePathStyle(testCase) != null) + { #> + serviceConfig.ForcePathStyle = <#=this.GetForcePathStyle(testCase).ToString().ToLower()#>; +<# + } + if (this.GetUseAccountIdRouting(testCase) != null) + { +#> + serviceConfig.UseAccountIdRouting = <#=this.GetUseAccountIdRouting(testCase).ToString().ToLower()#>; +<# + } + var sigV4aRegionSet = this.GetSigV4aRegionSet(testCase); + if (sigV4aRegionSet != null && sigV4aRegionSet.Length > 0) + { +#> + serviceConfig.SignatureVersion = "4a"; + serviceConfig.SigningRegion = "<#=string.Join(",", sigV4aRegionSet)#>"; +<# + } +#> + var serviceClient = new Amazon<#=this.Config.ClassName#>Client(serviceConfig); - - // TODO: Add any input from the test case to the request object. var request = new <#=modeledOperation.Name#>Request(); - // TODO: Handle when test cases are testing a failure condition. That means catching the exception and verifing we got the right exception. - var response = await serviceClient.<#=modeledOperation.Name#>Async(request); +<# + var input = testCase["input"] as JsonData; + if (input != null && input.IsObject) + { + foreach (string jsonKey in input.PropertyNames) + { + var propertyName = FindPropertyName(modeledOperation, jsonKey); + var value = input[jsonKey]; + if (value != null) + { + if (value.IsString) + { +#> + request.<#=propertyName#> = "<#=value.ToString()#>"; +<# + } + else if (value.IsInt) + { +#> + request.<#=propertyName#> = (int)<#=value#>; +<# + } + else if (value.IsBoolean) + { +#> + request.<#=propertyName#> = <#=value.ToString().ToLower()#>; +<# + } + else if (value.IsArray) + { + if (propertyName == "Tags") + { +#> + request.Tags = new List(); +<# + foreach (JsonData tag in value) + { + if (tag != null && tag.IsObject && tag["Key"] != null && tag["Value"] != null) + { +#> + request.Tags.Add(new Tag { Key = "<#=tag["Key"]#>", Value = "<#=tag["Value"]#>" }); +<# + } + } + } + else + { + // Check if all items are strings + bool allStrings = true; + foreach (JsonData item in value) + { + if (item != null && !item.IsString) + { + allStrings = false; + break; + } + } - await Task.CompletedTask; + if (allStrings) + { +#> + request.<#=propertyName#> = new List + { +<# + } + else + { +#> + request.<#=propertyName#> = new List + { +<# + } + var isFirst = true; + foreach (JsonData item in value) + { + if (item != null) + { + if (!isFirst) + { +#> + , +<# + } + if (item.IsString) + { +#> + "<#=item.ToString()#>" +<# + } + else if (item.IsInt) + { +#> + <#=item.ToString()#> +<# + } + else if (item.IsBoolean) + { +#> + <#=item.ToString().ToLower()#> +<# + } + else if (item.IsDouble) + { +#> + <#=item.ToString()#> +<# + } + isFirst = false; + } + } +#> + }; +<# + } + } + else if (value.IsObject) + { + if (propertyName == "Includes") + { +#> + request.<#=propertyName#> = new Filters + { +<# + var keyTypes = value["keyTypes"] as JsonData; + if (keyTypes != null && keyTypes.IsArray) + { + var keyTypeValues = new List(); + foreach (JsonData keyType in keyTypes) + { + if (keyType != null && keyType.IsString) + { + keyTypeValues.Add($"\"{keyType.ToString()}\""); + } + } + if (keyTypeValues.Count > 0) + { +#> + KeyTypes = new List { <#=string.Join(", ", keyTypeValues)#> } +<# + } + } +#> + }; +<# + } + } + } + } + } + + if (IsSuccessExpected(testCase)) + { +#> + var response = await serviceClient.<#=modeledOperation.Name#>Async(request); +<# + } + else + { + var errorId = GetExpectedErrorId(testCase); +#> + try + { + var response = await serviceClient.<#=modeledOperation.Name#>Async(request); + Assert.Fail("Expected <#=errorId ?? "an error response"#> exception, but the call succeeded."); + } + catch (Amazon<#=this.Config.ClassName#>Exception ex) + { +<# + if (!string.IsNullOrEmpty(errorId)) + { +#> + Assert.AreEqual("<#=errorId#>", ex.ErrorCode); +<# + } +#> + } +<# + } +#> } <# - } + } #> } } \ No newline at end of file