1
1
import { 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" ;
4
4
import { existsSync , readdirSync } from "fs" ;
5
5
import { join } from "path" ;
6
6
7
7
import { EndpointExpectation , ServiceModel , ServiceNamespace } from "./integration-test-types" ;
8
+ import { HttpRequest } from "@smithy/protocol-http" ;
8
9
9
10
describe ( "client list" , ( ) => {
10
11
const root = join ( __dirname , ".." , ".." ) ;
11
- const clientPackageNameList = readdirSync ( join ( root , "clients" ) ) ;
12
+ const clientPackageNameList = readdirSync ( join ( root , "clients" ) ) . filter ( ( f ) => f . startsWith ( "client-" ) ) ;
12
13
13
14
it ( "should be at least 300 clients" , ( ) => {
14
15
expect ( clientPackageNameList . length ) . toBeGreaterThan ( 300 ) ;
@@ -37,6 +38,7 @@ describe("client list", () => {
37
38
function runTestCases ( service : ServiceModel , namespace : ServiceNamespace ) {
38
39
const serviceId = service . traits [ "aws.api#service" ] . serviceId ;
39
40
const testCases = service . traits [ "smithy.rules#endpointTests" ] ?. testCases ;
41
+ const Client : any = Object . entries ( namespace ) . find ( ( [ k , v ] ) => k . endsWith ( "Client" ) ) ! [ 1 ] ;
40
42
41
43
const ruleSet = service . traits [ "smithy.rules#endpointRuleSet" ] ;
42
44
const defaultEndpointResolver = ( endpointParams : EndpointParams ) => resolveEndpoint ( ruleSet , { endpointParams } ) ;
@@ -46,14 +48,23 @@ function runTestCases(service: ServiceModel, namespace: ServiceNamespace) {
46
48
const { documentation, params = { } , expect : expectation , operationInputs } = testCase ;
47
49
params . serviceId = serviceId ;
48
50
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 ( ) => {
50
54
if ( "endpoint" in expectation ) {
51
55
const { endpoint } = expectation ;
52
56
if ( operationInputs ) {
53
57
for ( const operationInput of operationInputs ) {
54
58
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
+
57
68
const observed = defaultEndpointResolver ( endpointParams as EndpointParams ) ;
58
69
assertEndpointResolvedCorrectly ( endpoint , observed ) ;
59
70
}
@@ -106,3 +117,72 @@ function assertEndpointResolvedCorrectly(expected: EndpointExpectation["endpoint
106
117
expect ( observed . properties ?. authSchemes ) . toEqual ( authSchemes ) ;
107
118
}
108
119
}
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