Skip to content

Commit 08200d6

Browse files
authored
Merge pull request #421 from RachelTucker/JSDK_192
Explicit check for active job before recovering job in helpers
2 parents 696092d + 6b1ce30 commit 08200d6

File tree

5 files changed

+200
-7
lines changed

5 files changed

+200
-7
lines changed

ds3-sdk-integration/src/test/java/com/spectralogic/ds3client/integration/Smoke_Test.java

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.spectralogic.ds3client.commands.spectrads3.*;
2525
import com.spectralogic.ds3client.helpers.Ds3ClientHelpers;
2626
import com.spectralogic.ds3client.helpers.JobRecoveryException;
27+
import com.spectralogic.ds3client.helpers.JobRecoveryNotActiveException;
2728
import com.spectralogic.ds3client.helpers.ObjectCompletedListener;
2829
import com.spectralogic.ds3client.helpers.options.WriteJobOptions;
2930
import com.spectralogic.ds3client.integration.test.helpers.JobStatusHelper;
@@ -484,6 +485,47 @@ public void testRecoverWriteJob() throws IOException, JobRecoveryException, URIS
484485
}
485486
}
486487

488+
@Test (expected = JobRecoveryNotActiveException.class)
489+
public void testRecoverWriteJobCanceledJob() throws IOException, URISyntaxException, JobRecoveryException {
490+
final String bucketName = "test_canceled_recover_write_job_bucket";
491+
final String book1 = "beowulf.txt";
492+
final String book2 = "ulysses.txt";
493+
494+
try {
495+
HELPERS.ensureBucketExists(bucketName, envDataPolicyId);
496+
497+
final Path objPath1 = ResourceUtils.loadFileResource(RESOURCE_BASE_NAME + book1);
498+
final Path objPath2 = ResourceUtils.loadFileResource(RESOURCE_BASE_NAME + book2);
499+
final Ds3Object obj1 = new Ds3Object(book1, Files.size(objPath1));
500+
final Ds3Object obj2 = new Ds3Object(book2, Files.size(objPath2));
501+
502+
final Ds3ClientHelpers.Job job = Ds3ClientHelpers.wrap(client).startWriteJob(bucketName, Lists.newArrayList(obj1, obj2));
503+
504+
final PutObjectResponse putResponse1 = client.putObject(new PutObjectRequest(
505+
job.getBucketName(),
506+
book1,
507+
new ResourceObjectPutter(RESOURCE_BASE_NAME).buildChannel(book1),
508+
job.getJobId().toString(),
509+
0,
510+
Files.size(objPath1)));
511+
assertThat(putResponse1, is(notNullValue()));
512+
513+
// Cancel write job and attempt recovery
514+
client.cancelActiveJobSpectraS3(new CancelActiveJobSpectraS3Request(job.getJobId()));
515+
516+
// Attempt recovery of canceled job
517+
HELPERS.recoverWriteJob(job.getJobId());
518+
assert false;
519+
} finally {
520+
deleteAllContents(client, bucketName);
521+
}
522+
}
523+
524+
@Test (expected = JobRecoveryNotActiveException.class)
525+
public void testRecoverWriteJobDoesNotExist() throws IOException, JobRecoveryException {
526+
HELPERS.recoverWriteJob(UUID.randomUUID());
527+
}
528+
487529
@Test
488530
public void verifySendCrc32cChecksum() throws IOException, URISyntaxException {
489531
final String bucketName = "crc_32_bucket";
@@ -659,13 +701,73 @@ public void testRecoverReadJob() throws IOException, JobRecoveryException, URISy
659701

660702
} finally {
661703
deleteAllContents(client, bucketName);
662-
for( final Path tempFile : Files.newDirectoryStream(dirPath) ){
704+
for (final Path tempFile : Files.newDirectoryStream(dirPath) ){
663705
Files.delete(tempFile);
664706
}
665707
Files.delete(dirPath);
666708
}
667709
}
668710

711+
@Test (expected = JobRecoveryNotActiveException.class)
712+
public void testRecoverReadJobCanceledJob() throws IOException, JobRecoveryException, URISyntaxException {
713+
final String bucketName = "test_canceled_recover_read_job_bucket";
714+
final String book1 = "beowulf.txt";
715+
final String book2 = "ulysses.txt";
716+
final Path objPath1 = ResourceUtils.loadFileResource(RESOURCE_BASE_NAME + book1);
717+
final Path objPath2 = ResourceUtils.loadFileResource(RESOURCE_BASE_NAME + book2);
718+
final Ds3Object obj1 = new Ds3Object(book1, Files.size(objPath1));
719+
final Ds3Object obj2 = new Ds3Object(book2, Files.size(objPath2));
720+
721+
final Path dirPath = FileSystems.getDefault().getPath("output_canceled_job");
722+
if (!Files.exists(dirPath)) {
723+
Files.createDirectory(dirPath);
724+
}
725+
726+
try {
727+
HELPERS.ensureBucketExists(bucketName, envDataPolicyId);
728+
729+
final Ds3ClientHelpers.Job putJob = HELPERS.startWriteJob(bucketName, Lists.newArrayList(obj1, obj2));
730+
putJob.transfer(new ResourceObjectPutter(RESOURCE_BASE_NAME));
731+
732+
final FileChannel channel1 = FileChannel.open(
733+
dirPath.resolve(book1),
734+
StandardOpenOption.WRITE,
735+
StandardOpenOption.CREATE,
736+
StandardOpenOption.TRUNCATE_EXISTING
737+
);
738+
739+
final Ds3ClientHelpers.Job readJob = HELPERS.startReadJob(bucketName, Lists.newArrayList(obj1, obj2));
740+
final GetObjectResponse readResponse1 = client.getObject(
741+
new GetObjectRequest(
742+
bucketName,
743+
book1,
744+
channel1,
745+
readJob.getJobId().toString(),
746+
0));
747+
748+
assertThat(readResponse1, is(notNullValue()));
749+
assertThat(readResponse1.getObjectSize(), is(notNullValue()));
750+
751+
// Cancel active job
752+
client.cancelActiveJobSpectraS3(new CancelActiveJobSpectraS3Request(readJob.getJobId()));
753+
754+
// Attempt recovery of canceled job
755+
HELPERS.recoverReadJob(readJob.getJobId());
756+
assert false;
757+
} finally {
758+
deleteAllContents(client, bucketName);
759+
for (final Path tempFile : Files.newDirectoryStream(dirPath) ){
760+
Files.delete(tempFile);
761+
}
762+
Files.delete(dirPath);
763+
}
764+
}
765+
766+
@Test (expected = JobRecoveryNotActiveException.class)
767+
public void testRecoverReadJobDoesNotExist() throws IOException, JobRecoveryException {
768+
HELPERS.recoverReadJob(UUID.randomUUID());
769+
}
770+
669771
@Test
670772
public void putDirectory() throws IOException {
671773
assumeVersion1_2(client);

ds3-sdk/src/main/java/com/spectralogic/ds3client/helpers/Ds3ClientHelpersImpl.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,10 @@ private Ds3ClientHelpers.Job innerStartReadAllJob(final String bucket, final Rea
210210

211211
@Override
212212
public Ds3ClientHelpers.Job recoverWriteJob(final UUID jobId) throws IOException, JobRecoveryException {
213+
innerVerifyJobActive(jobId);
213214
final ModifyJobSpectraS3Response jobResponse = this.client.modifyJobSpectraS3(new ModifyJobSpectraS3Request(jobId.toString()));
214215
if (JobRequestType.PUT != jobResponse.getMasterObjectListResult().getRequestType()) {
215-
throw new JobRecoveryException(
216+
throw new JobRecoveryTypeException(
216217
RequestType.PUT.toString(),
217218
jobResponse.getMasterObjectListResult().getRequestType().toString());
218219
}
@@ -230,9 +231,10 @@ public Ds3ClientHelpers.Job recoverWriteJob(final UUID jobId) throws IOException
230231
@Override
231232
//TODO add a partial object read recovery method. That method will require the list of partial objects.
232233
public Ds3ClientHelpers.Job recoverReadJob(final UUID jobId) throws IOException, JobRecoveryException {
234+
innerVerifyJobActive(jobId);
233235
final ModifyJobSpectraS3Response jobResponse = this.client.modifyJobSpectraS3(new ModifyJobSpectraS3Request(jobId.toString()));
234236
if (JobRequestType.GET != jobResponse.getMasterObjectListResult().getRequestType()){
235-
throw new JobRecoveryException(
237+
throw new JobRecoveryTypeException(
236238
RequestType.GET.toString(),
237239
jobResponse.getMasterObjectListResult().getRequestType().toString() );
238240
}
@@ -246,6 +248,23 @@ public Ds3ClientHelpers.Job recoverReadJob(final UUID jobId) throws IOException,
246248
this.eventRunner);
247249
}
248250

251+
/**
252+
* Verifies that the specified job is active. If the job is not active, then a
253+
* JobRecoveryNotActiveException is thrown.
254+
* @throws IOException
255+
* @throws JobRecoveryNotActiveException
256+
*/
257+
private void innerVerifyJobActive(final UUID jobId) throws IOException, JobRecoveryNotActiveException {
258+
try {
259+
client.getActiveJobSpectraS3(new GetActiveJobSpectraS3Request(jobId));
260+
} catch (final FailedRequestException e) {
261+
if (e.getStatusCode() == 404) {
262+
throw new JobRecoveryNotActiveException(jobId, e);
263+
}
264+
throw e;
265+
}
266+
}
267+
249268
@Override
250269
public void ensureBucketExists(final String bucket) throws IOException {
251270
final HeadBucketResponse response = this.client.headBucket(new HeadBucketRequest(bucket));

ds3-sdk/src/main/java/com/spectralogic/ds3client/helpers/JobRecoveryException.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818
public class JobRecoveryException extends Exception {
1919
private static final long serialVersionUID = -4418169724222972364L;
2020

21-
JobRecoveryException(final String expectedType, final String actualType) {
22-
super(buildMessage(expectedType, actualType));
21+
public JobRecoveryException(final String message) {
22+
super(message);
2323
}
2424

25-
private static String buildMessage(final String expectedType, final String actualType) {
26-
return String.format("Expected job type '%s' but the actual job was of type '%s'.", expectedType, actualType);
25+
public JobRecoveryException(final String message, final Throwable cause) {
26+
super(message, cause);
2727
}
2828
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* ****************************************************************************
3+
* Copyright 2014-2016 Spectra Logic Corporation. All Rights Reserved.
4+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use
5+
* this file except in compliance with the License. A copy of the License is located at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* or in the "license" file accompanying this file.
10+
* This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11+
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
12+
* specific language governing permissions and limitations under the License.
13+
* ****************************************************************************
14+
*/
15+
16+
package com.spectralogic.ds3client.helpers;
17+
18+
import java.util.UUID;
19+
20+
/**
21+
* This exception represents a failure of an attempted recovery of a job
22+
* performed using {@link Ds3ClientHelpers#recoverReadJob(UUID)} or
23+
* {@link Ds3ClientHelpers#recoverWriteJob(UUID)} that is caused by the
24+
* specified job not being active.
25+
*/
26+
public class JobRecoveryNotActiveException extends JobRecoveryException {
27+
28+
public JobRecoveryNotActiveException(final UUID jobId, final Throwable cause) {
29+
super(buildMessage(jobId), cause);
30+
}
31+
32+
private static String buildMessage(final UUID jobId) {
33+
return String.format("Cannot recover inactive job '%s'", jobId.toString());
34+
}
35+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* ****************************************************************************
3+
* Copyright 2014-2016 Spectra Logic Corporation. All Rights Reserved.
4+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use
5+
* this file except in compliance with the License. A copy of the License is located at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* or in the "license" file accompanying this file.
10+
* This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11+
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
12+
* specific language governing permissions and limitations under the License.
13+
* ****************************************************************************
14+
*/
15+
16+
package com.spectralogic.ds3client.helpers;
17+
18+
import com.spectralogic.ds3client.models.JobRequestType;
19+
20+
import java.util.UUID;
21+
22+
/**
23+
* This exception is thrown when an attempted recover is performed using {@link Ds3ClientHelpers}
24+
* and the {@link JobRequestType} of the specified job does not match the type of recovery to be performed.
25+
* {@link Ds3ClientHelpers#recoverReadJob(UUID)} requires the specified job to be of type {@link JobRequestType#GET}.
26+
* {@link Ds3ClientHelpers#recoverWriteJob(UUID)} requires the specified job to be of type {@link JobRequestType#PUT}.
27+
*/
28+
public class JobRecoveryTypeException extends JobRecoveryException {
29+
30+
public JobRecoveryTypeException(final String expectedType, final String actualType) {
31+
super(buildMessage(expectedType, actualType));
32+
}
33+
34+
private static String buildMessage(final String expectedType, final String actualType) {
35+
return String.format("Expected job type '%s' but the actual job was of type '%s'.", expectedType, actualType);
36+
}
37+
}

0 commit comments

Comments
 (0)