@@ -183,6 +183,17 @@ private void generateServerOperationTests(OperationShape operation, OperationInd
183
183
onlyIfProtocolMatches (testCase , () -> generateServerResponseTest (operation , testCase ));
184
184
}
185
185
});
186
+ // 3. Generate test cases for each error on each operation.
187
+ for (StructureShape error : operationIndex .getErrors (operation )) {
188
+ if (!error .hasTag ("server-only" )) {
189
+ error .getTrait (HttpResponseTestsTrait .class ).ifPresent (trait -> {
190
+ for (HttpResponseTestCase testCase : trait .getTestCasesFor (AppliesTo .SERVER )) {
191
+ onlyIfProtocolMatches (testCase ,
192
+ () -> generateServerErrorResponseTest (operation , error , testCase ));
193
+ }
194
+ });
195
+ }
196
+ }
186
197
}
187
198
}
188
199
@@ -288,8 +299,7 @@ private void generateServerRequestTest(OperationShape operation, HttpRequestTest
288
299
});
289
300
290
301
String getHandlerName = "get" + handlerSymbol .getName ();
291
- writer .addImport (getHandlerName , getHandlerName ,
292
- "./protocols/" + ProtocolGenerator .getSanitizedName (protocolGenerator .getName ()));
302
+ writer .addImport (getHandlerName , null , "./server/" );
293
303
294
304
// Cast the service as any so TS will ignore the fact that the type being passed in is incomplete.
295
305
writer .write ("const handler = $L(testService as $T);" , getHandlerName , serviceSymbol );
@@ -477,8 +487,6 @@ private String registerBodyComparatorStub(String mediaType) {
477
487
public void generateServerResponseTest (OperationShape operation , HttpResponseTestCase testCase ) {
478
488
Symbol serviceSymbol = serverSymbolProvider .toSymbol (service );
479
489
Symbol operationSymbol = serverSymbolProvider .toSymbol (operation );
480
- Symbol handlerSymbol = serviceSymbol .expectProperty ("handler" , Symbol .class );
481
- Symbol serviceOperationsSymbol = serviceSymbol .expectProperty ("operations" , Symbol .class );
482
490
testCase .getDocumentation ().ifPresent (writer ::writeDocs );
483
491
String testName = testCase .getId () + ":ServerResponse" ;
484
492
writer .openBlock ("it($S, async () => {" , "});\n " , testName , () -> {
@@ -497,42 +505,7 @@ public void generateServerResponseTest(OperationShape operation, HttpResponseTes
497
505
}
498
506
});
499
507
});
500
-
501
- writer .write ("const service: any = new TestService()" );
502
-
503
- // There's a lot of setup here, including creating our own mux, serializers list, and ultimately
504
- // our own service handler. This is largely in service of avoiding having to go through the
505
- // request deserializer
506
- writer .addImport ("httpbinding" , null , "@aws-smithy/server-common" );
507
- writer .openBlock ("const testMux = new httpbinding.HttpBindingMux<$S, keyof $T>([" , "]);" ,
508
- service .getId ().getName (), serviceSymbol , () -> {
509
- writer .openBlock ("new httpbinding.UriSpec<$S, $S>('POST', [], [], {" , "})," ,
510
- service .getId ().getName (), operation .getId ().getName (), () -> {
511
- writer .write ("service: $S," , service .getId ().getName ());
512
- writer .write ("operation: $S," , operation .getId ().getName ());
513
- });
514
- });
515
-
516
- writer .write ("const request = new HttpRequest({method: 'POST', hostname: 'example.com'});" );
517
-
518
- String serializerName = ProtocolGenerator .getGenericSerFunctionName (operationSymbol ) + "Response" ;
519
- writer .addImport (serializerName , serializerName ,
520
- "./protocols/" + ProtocolGenerator .getSanitizedName (protocolGenerator .getName ()));
521
-
522
- writer .addImport ("OperationSerializer" , "__OperationSerializer" , "@aws-smithy/server-common" );
523
- writer .openBlock ("const serFn: (op: $1T) => __OperationSerializer<$2T, $1T> = (op) => {" , "};" ,
524
- serviceOperationsSymbol , serviceSymbol , () -> {
525
- writer .openBlock ("return {" , "};" , () -> {
526
- writer .write ("serialize: $L," , serializerName );
527
- writer .openBlock ("deserialize: (output: any, context: any): Promise<any> => {" , "}," , () -> {
528
- writer .write ("return Promise.resolve({});" );
529
- });
530
- });
531
- });
532
-
533
- writer .write ("const handler = new $T(service, testMux, serFn);" , handlerSymbol );
534
- writer .write ("let r = await handler.handle(request)" ).write ("" );
535
- writeHttpResponseAssertions (testCase );
508
+ writeServerResponseTest (operation , testCase );
536
509
});
537
510
}
538
511
@@ -554,6 +527,76 @@ private void generateResponseTest(OperationShape operation, HttpResponseTestCase
554
527
});
555
528
}
556
529
530
+ private void generateServerErrorResponseTest (
531
+ OperationShape operation ,
532
+ StructureShape error ,
533
+ HttpResponseTestCase testCase
534
+ ) {
535
+ Symbol serviceSymbol = serverSymbolProvider .toSymbol (service );
536
+ Symbol operationSymbol = serverSymbolProvider .toSymbol (operation );
537
+ Symbol outputType = operationSymbol .expectProperty ("outputType" , Symbol .class );
538
+ Symbol errorSymbol = serverSymbolProvider .toSymbol (error );
539
+ ErrorTrait errorTrait = error .expectTrait (ErrorTrait .class );
540
+ testCase .getDocumentation ().ifPresent (writer ::writeDocs );
541
+ String testName = testCase .getId () + ":ServerErrorResponse" ;
542
+ writer .openBlock ("it($S, async () => {" , "});\n " , testName , () -> {
543
+ writer .openBlock ("class TestService implements Partial<$T> {" , "}" , serviceSymbol , () -> {
544
+ writer .openBlock ("$L(input: any, request: HttpRequest): $T {" , "}" ,
545
+ operationSymbol .getName (), outputType , () -> {
546
+ writer .writeInline ("const response = " );
547
+ testCase .getParams ().accept (new CommandInputNodeVisitor (error , true ));
548
+ writer .openBlock ("const error: $T = {" , "};" , errorSymbol , () -> {
549
+ writer .write ("...response," );
550
+ writer .write ("name: $S," , error .getId ().getName ());
551
+ writer .write ("$$fault: $S," , errorTrait .isClientError () ? "client" : "server" );
552
+ writer .write ("$$metadata: {}," );
553
+ });
554
+ writer .write ("throw error;" );
555
+ });
556
+ });
557
+ writeServerResponseTest (operation , testCase );
558
+ });
559
+ }
560
+
561
+ private void writeServerResponseTest (OperationShape operation , HttpResponseTestCase testCase ) {
562
+ Symbol serviceSymbol = serverSymbolProvider .toSymbol (service );
563
+ Symbol operationSymbol = serverSymbolProvider .toSymbol (operation );
564
+ Symbol handlerSymbol = serviceSymbol .expectProperty ("handler" , Symbol .class );
565
+ Symbol serializerSymbol = operationSymbol .expectProperty ("serializerType" , Symbol .class );
566
+ Symbol serviceOperationsSymbol = serviceSymbol .expectProperty ("operations" , Symbol .class );
567
+ writer .write ("const service: any = new TestService()" );
568
+
569
+ // There's a lot of setup here, including creating our own mux, serializers list, and ultimately
570
+ // our own service handler. This is largely in service of avoiding having to go through the
571
+ // request deserializer
572
+ writer .addImport ("httpbinding" , null , "@aws-smithy/server-common" );
573
+ writer .openBlock ("const testMux = new httpbinding.HttpBindingMux<$S, keyof $T>([" , "]);" ,
574
+ service .getId ().getName (), serviceSymbol , () -> {
575
+ writer .openBlock ("new httpbinding.UriSpec<$S, $S>('POST', [], [], {" , "})," ,
576
+ service .getId ().getName (), operation .getId ().getName (), () -> {
577
+ writer .write ("service: $S," , service .getId ().getName ());
578
+ writer .write ("operation: $S," , operation .getId ().getName ());
579
+ });
580
+ });
581
+
582
+ writer .write ("const request = new HttpRequest({method: 'POST', hostname: 'example.com'});" );
583
+
584
+ writer .openBlock ("class TestSerializer extends $T {" , "}" , serializerSymbol , () -> {
585
+ writer .openBlock ("deserialize = (output: any, context: any): Promise<any> => {" , "};" , () -> {
586
+ writer .write ("return Promise.resolve({});" );
587
+ });
588
+ });
589
+
590
+ writer .addImport ("SmithyException" , "__SmithyException" , "@aws-sdk/smithy-client" );
591
+ writer .addImport ("OperationSerializer" , "__OperationSerializer" , "@aws-smithy/server-common" );
592
+ writer .openBlock ("const serFn: (op: $1T) => __OperationSerializer<$2T, $1T, __SmithyException> = (op) =>"
593
+ + " { return new TestSerializer(); };" , serviceOperationsSymbol , serviceSymbol );
594
+
595
+ writer .write ("const handler = new $T(service, testMux, serFn);" , handlerSymbol );
596
+ writer .write ("let r = await handler.handle(request)" ).write ("" );
597
+ writeHttpResponseAssertions (testCase );
598
+ }
599
+
557
600
private void generateErrorResponseTest (
558
601
OperationShape operation ,
559
602
StructureShape error ,
0 commit comments