11import { resolveParams } from "@smithy/middleware-endpoint" ;
2- import { EndpointV2 } from "@smithy/types" ;
3- import { resolveEndpoint , EndpointParams } from "@smithy/util-endpoints" ;
2+ import { EndpointV2 , RelativeMiddlewareOptions } from "@smithy/types" ;
3+ import { EndpointParams , resolveEndpoint } from "@smithy/util-endpoints" ;
44import { existsSync , readdirSync } from "fs" ;
55import { join } from "path" ;
66
77import { EndpointExpectation , ServiceModel , ServiceNamespace } from "./integration-test-types" ;
8+ import { HttpRequest } from "@smithy/protocol-http" ;
89
910describe ( "client list" , ( ) => {
1011 const root = join ( __dirname , ".." , ".." ) ;
11- const clientPackageNameList = readdirSync ( join ( root , "clients" ) ) ;
12+ const clientPackageNameList = readdirSync ( join ( root , "clients" ) ) . filter ( ( f ) => f . startsWith ( "client-" ) ) ;
1213
1314 it ( "should be at least 300 clients" , ( ) => {
1415 expect ( clientPackageNameList . length ) . toBeGreaterThan ( 300 ) ;
@@ -37,6 +38,7 @@ describe("client list", () => {
3738function runTestCases ( service : ServiceModel , namespace : ServiceNamespace ) {
3839 const serviceId = service . traits [ "aws.api#service" ] . serviceId ;
3940 const testCases = service . traits [ "smithy.rules#endpointTests" ] ?. testCases ;
41+ const Client : any = Object . entries ( namespace ) . find ( ( [ k , v ] ) => k . endsWith ( "Client" ) ) ! [ 1 ] ;
4042
4143 const ruleSet = service . traits [ "smithy.rules#endpointRuleSet" ] ;
4244 const defaultEndpointResolver = ( endpointParams : EndpointParams ) => resolveEndpoint ( ruleSet , { endpointParams } ) ;
@@ -46,14 +48,23 @@ function runTestCases(service: ServiceModel, namespace: ServiceNamespace) {
4648 const { documentation, params = { } , expect : expectation , operationInputs } = testCase ;
4749 params . serviceId = serviceId ;
4850
49- it ( documentation || "undocumented testcase" , async ( ) => {
51+ const test = Client . name === "DynamoDBClient" && "AccountId" in params ? it . skip : it ;
52+
53+ test ( documentation || "undocumented testcase" , async ( ) => {
5054 if ( "endpoint" in expectation ) {
5155 const { endpoint } = expectation ;
5256 if ( operationInputs ) {
5357 for ( const operationInput of operationInputs ) {
5458 const { operationName, operationParams = { } } = operationInput ;
55- const command = namespace [ `${ operationName } Command` ] ;
56- const endpointParams = await resolveParams ( operationParams , command , params ) ;
59+ const Command = namespace [ `${ operationName } Command` ] ;
60+ const endpointParams = await resolveParams ( operationParams , Command , mapClientConfig ( params ) ) ;
61+
62+ // todo: Use an actual client for a more integrated test.
63+ // todo: This call returns an intercepted EndpointV2 object that can replace the one
64+ // todo: used below.
65+ void useClient ;
66+ void [ Client , params , Command , operationParams ] ;
67+
5768 const observed = defaultEndpointResolver ( endpointParams as EndpointParams ) ;
5869 assertEndpointResolvedCorrectly ( endpoint , observed ) ;
5970 }
@@ -106,3 +117,72 @@ function assertEndpointResolvedCorrectly(expected: EndpointExpectation["endpoint
106117 expect ( observed . properties ?. authSchemes ) . toEqual ( authSchemes ) ;
107118 }
108119}
120+
121+ /**
122+ * Makes a client operation return its EndpointV2 instead of making a request.
123+ */
124+ const requestInterceptorMiddleware = ( next : any , context : any ) => async ( args : any ) => {
125+ const { request } = args ;
126+ if ( HttpRequest . isInstance ( request ) ) {
127+ const endpoint = context . endpointV2 ;
128+ return {
129+ response : {
130+ statusCode : 200 ,
131+ } ,
132+ output : {
133+ ...endpoint ,
134+ url : {
135+ protocol : request . protocol ,
136+ hostname : request . hostname ,
137+ pathname : request . path ,
138+ href : `${ request . protocol } //${ request . hostname } ${ request . path } ` ,
139+ } as URL ,
140+ } ,
141+ } as {
142+ output : EndpointV2 ;
143+ } ;
144+ }
145+ throw new Error ( "Request must not continue beyond serialization step." ) ;
146+ } ;
147+ const requestInterceptorMiddlewareOptions : RelativeMiddlewareOptions = {
148+ name : "requestInterceptorMiddleware" ,
149+ override : true ,
150+ toMiddleware : "serializerMiddleware" ,
151+ relation : "after" ,
152+ } ;
153+
154+ const paramMap = {
155+ Region : "region" ,
156+ UseFIPS : "useFipsEndpoint" ,
157+ UseDualStack : "useDualstackEndpoint" ,
158+ ForcePathStyle : "forcePathStyle" ,
159+ Accelerate : "useAccelerateEndpoint" ,
160+ DisableMRAP : "disableMultiregionAccessPoints" ,
161+ DisableMultiRegionAccessPoints : "disableMultiregionAccessPoints" ,
162+ UseArnRegion : "useArnRegion" ,
163+ Endpoint : "endpoint" ,
164+ UseGlobalEndpoint : "useGlobalEndpoint" ,
165+ } ;
166+
167+ async function useClient ( Client : any , Command : any , clientConfig : any , input : any ) : Promise < EndpointV2 > {
168+ const client = new Client ( {
169+ ...mapClientConfig ( clientConfig ) ,
170+ credentials : {
171+ accessKeyId : "ENDPOINTS_TEST" ,
172+ secretAccessKey : "ENDPOINTS_TEST" ,
173+ } ,
174+ } ) ;
175+ client . middlewareStack . addRelativeTo ( requestInterceptorMiddleware , requestInterceptorMiddlewareOptions ) ;
176+ const command = new Command ( input ) ;
177+ const observed : EndpointV2 = await client . send ( command ) ;
178+ return observed ;
179+ }
180+
181+ function mapClientConfig ( params : any ) {
182+ return Object . entries ( params ) . reduce ( ( acc : any , cur : [ string , any ] ) => {
183+ const [ k , v ] = cur ;
184+ const key = paramMap [ k as keyof typeof paramMap ] ?? k ;
185+ acc [ key ] = v ;
186+ return acc ;
187+ } , { } as any ) ;
188+ }
0 commit comments