2525import static com .github .tomakehurst .wiremock .client .WireMock .urlEqualTo ;
2626import static com .github .tomakehurst .wiremock .client .WireMock .urlPathMatching ;
2727import static com .github .tomakehurst .wiremock .core .WireMockConfiguration .wireMockConfig ;
28+ import static org .assertj .core .api .Assertions .assertThat ;
2829import static org .assertj .core .api .Assertions .assertThatThrownBy ;
2930
3031import com .github .tomakehurst .wiremock .WireMockServer ;
31- import com .google .common .jimfs .Configuration ;
32- import com .google .common .jimfs .Jimfs ;
32+ import com .github .tomakehurst .wiremock .http .Fault ;
3333import java .io .IOException ;
3434import java .io .OutputStream ;
3535import java .io .UncheckedIOException ;
3636import java .net .URI ;
37- import java .nio .file .FileSystem ;
3837import java .nio .file .Files ;
3938import java .nio .file .Path ;
4039import java .nio .file .StandardOpenOption ;
40+ import java .util .concurrent .CompletionException ;
4141import org .junit .jupiter .api .AfterAll ;
4242import org .junit .jupiter .api .AfterEach ;
4343import org .junit .jupiter .api .BeforeAll ;
5050import software .amazon .awssdk .services .s3 .S3AsyncClient ;
5151import software .amazon .awssdk .services .s3 .model .S3Exception ;
5252import software .amazon .awssdk .transfer .s3 .S3TransferManager ;
53+ import software .amazon .awssdk .transfer .s3 .model .FileUpload ;
54+ import software .amazon .awssdk .transfer .s3 .model .ResumableFileUpload ;
5355import software .amazon .awssdk .transfer .s3 .model .UploadFileRequest ;
5456
5557/**
5658 * WireMock test for verifying the DefaultFileUpload codepath.
5759 */
5860public class DefaultFileUploadWireMockTest {
5961 private static final WireMockServer wireMock = new WireMockServer (wireMockConfig ().dynamicPort ());
60- private static final FileSystem testFs = Jimfs .newFileSystem (Configuration .unix ());
6162 private static Path testFile ;
6263 private static S3AsyncClient s3 ;
6364
6465 @ BeforeAll
65- public static void setup () {
66- testFile = testFs . getPath ( "/ 32mib.dat" );
66+ public static void setup () throws IOException {
67+ testFile = Files . createTempFile ( " 32mib" , " .dat" );
6768 writeTestFile (testFile , 32 * 1024 * 1024 );
6869 wireMock .start ();
6970 }
7071
7172 @ AfterAll
7273 public static void teardown () throws IOException {
73- testFs . close ( );
74+ Files . deleteIfExists ( testFile );
7475 wireMock .stop ();
7576 }
7677
@@ -98,29 +99,14 @@ public void methodTeardown() {
9899 @ Test
99100 void retryableErrorDuringUpload_shouldSupportRetries () {
100101 S3TransferManager tm = S3TransferManager .builder ().s3Client (s3 ).build ();
101-
102- String mpuInitBody = ""
103- + "<?xml version=\" 1.0\" encoding=\" UTF-8\" ?>\n "
104- + "<InitiateMultipartUploadResult>\n "
105- + " <Bucket>bucket</Bucket>\n "
106- + " <Key>key</Key>\n "
107- + " <UploadId>uploadId</UploadId>\n "
108- + "</InitiateMultipartUploadResult>" ;
109-
110- wireMock .stubFor (post (urlEqualTo ("/bucket/key?uploads" ))
111- .willReturn (aResponse ()
112- .withStatus (200 )
113- .withBody (mpuInitBody )));
102+ stubCreateMpuSuccessfulResponse ();
114103
115104 wireMock .stubFor (put (anyUrl ())
116105 .willReturn (aResponse ()
117106 .withStatus (500 )
118107 .withBody ("Internal Error" )));
119108
120- UploadFileRequest request = UploadFileRequest .builder ()
121- .source (testFile )
122- .putObjectRequest (put -> put .bucket ("bucket" ).key ("key" ))
123- .build ();
109+ UploadFileRequest request = createUploadFileRequest ();
124110
125111 assertThatThrownBy (() -> tm .uploadFile (request ).completionFuture ().join ())
126112 .hasCauseInstanceOf (S3Exception .class );
@@ -131,8 +117,57 @@ void retryableErrorDuringUpload_shouldSupportRetries() {
131117 .withQueryParam ("partNumber" , matching ("1" )));
132118 }
133119
120+ @ Test
121+ void connectionFaultDuringUpload_shouldSaveStateOfUpload () {
122+ S3TransferManager tm = S3TransferManager .builder ().s3Client (s3 ).build ();
123+
124+ stubCreateMpuSuccessfulResponse ();
125+
126+ wireMock .stubFor (put (urlPathMatching ("/bucket/key?partNumber=1&uploadId=uploadId" ))
127+ .willReturn (aResponse ()
128+ .withStatus (200 )
129+ .withBody ("<Part><PartNumber>1</PartNumber><ETag>\" etag1\" </ETag></Part>" )));
130+
131+ wireMock .stubFor (put (urlPathMatching ("/bucket/key?partNumber=2&uploadId=uploadId" ))
132+ .willReturn (aResponse ()
133+ .withFault (Fault .CONNECTION_RESET_BY_PEER )));
134+
135+ UploadFileRequest request = createUploadFileRequest ();
136+
137+ FileUpload fileUpload = null ;
138+ try {
139+ tm .uploadFile (request );
140+ } catch (Exception e ) {
141+ assertThat (e ).isInstanceOf (CompletionException .class );
142+ ResumableFileUpload resumableFileUpload = fileUpload .pause ();
143+ assertThat (resumableFileUpload .multipartUploadId ()).isPresent ();
144+ assertThat (resumableFileUpload .multipartUploadId ().get ()).isEqualTo ("uploadId" );
145+ }
146+ }
147+
148+ private void stubCreateMpuSuccessfulResponse () {
149+ String mpuInitBody = "<?xml version=\" 1.0\" encoding=\" UTF-8\" ?>\n "
150+ + "<InitiateMultipartUploadResult>\n "
151+ + " <Bucket>bucket</Bucket>\n "
152+ + " <Key>key</Key>\n "
153+ + " <UploadId>uploadId</UploadId>\n "
154+ + "</InitiateMultipartUploadResult>" ;
155+
156+ wireMock .stubFor (post (urlEqualTo ("/bucket/key?uploads" ))
157+ .willReturn (aResponse ()
158+ .withStatus (200 )
159+ .withBody (mpuInitBody )));
160+ }
161+
162+ private UploadFileRequest createUploadFileRequest () {
163+ return UploadFileRequest .builder ()
164+ .source (testFile )
165+ .putObjectRequest (put -> put .bucket ("bucket" ).key ("key" ))
166+ .build ();
167+ }
168+
134169 private static void writeTestFile (Path file , long size ) {
135- try (OutputStream os = Files .newOutputStream (file , StandardOpenOption .CREATE_NEW )) {
170+ try (OutputStream os = Files .newOutputStream (file , StandardOpenOption .CREATE )) {
136171 byte [] buff = new byte [4096 ];
137172 long remaining = size ;
138173 while (remaining != 0 ) {
0 commit comments