// // Copyright 2015-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). // You may not use this file except in compliance with the License. // A copy of the License is located at // // http://aws.amazon.com/apache2.0 // // or in the "license" file accompanying this file. This file is distributed // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either // express or implied. See the License for the specific language governing // permissions and limitations under the License. // package com.amazonaws.devicefarm; import com.amazonaws.services.devicefarm.AWSDeviceFarmClient; import com.amazonaws.services.devicefarm.model.CreateUploadRequest; import com.amazonaws.services.devicefarm.model.GetUploadRequest; import com.amazonaws.services.devicefarm.model.GetUploadResult; import com.amazonaws.services.devicefarm.model.Project; import com.amazonaws.services.devicefarm.model.Upload; import com.amazonaws.services.devicefarm.model.UploadType; import com.google.common.collect.Lists; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.FileEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.gradle.api.logging.Logger; import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * Artifact uploader for AWS Device Farm */ public class DeviceFarmUploader { private final AWSDeviceFarmClient api; private final Logger logger; private final ExecutorService uploadExecutor; public DeviceFarmUploader(final AWSDeviceFarmClient api, final Logger logger) { this.api = api; this.logger = logger; this.uploadExecutor = Executors.newCachedThreadPool(); } /** * Upload a single file, waits for upload to complete. * * @param file the file * @param project the project * @param uploadType the upload type * @return upload object */ public Upload upload(final File file, final Project project, final UploadType uploadType) { if (!(file.exists() && file.canRead())) { throw new DeviceFarmException(String.format("File %s does not exist or is not readable", file)); } final CreateUploadRequest appUploadRequest = new CreateUploadRequest() .withName(file.getName()) .withProjectArn(project.getArn()) .withContentType("application/octet-stream") .withType(uploadType.toString()); final Upload upload = api.createUpload(appUploadRequest).getUpload(); final CloseableHttpClient httpClient = HttpClients.createDefault(); final HttpPut httpPut = new HttpPut(upload.getUrl()); httpPut.setHeader("Content-Type", upload.getContentType()); final FileEntity entity = new FileEntity(file); httpPut.setEntity(entity); writeToLog(String.format("Uploading %s to S3", file.getName())); final HttpResponse response; try { response = httpClient.execute(httpPut); } catch (IOException e) { throw new DeviceFarmException(String.format("Error uploading artifact %s", file), e); } if (response.getStatusLine().getStatusCode() != 200) { throw new DeviceFarmException(String.format("Upload returned non-200 responses: %s", response.getStatusLine().getStatusCode())); } waitForUpload(file, upload); return upload; } public Collection<Upload> batchUpload(final List<File> artifacts, final Project project, final UploadType uploadType) { List<Future<Upload>> futures = Lists.newArrayList(); // Upload each artifact and create a future for it. for (final File file : artifacts) { futures.add(uploadExecutor.submit( new Callable<Upload>() { @Override public Upload call() throws Exception { return upload(file, project, uploadType); } } )); } List<Upload> uploads = Lists.newArrayList(); // Check future results and append the upload results to a list. for (Future<Upload> f : futures) { try { uploads.add(f.get()); } catch (Exception e) { throw new DeviceFarmException(e); } } return uploads; } private void waitForUpload(final File file, final Upload upload) { while (true) { GetUploadRequest describeUploadRequest = new GetUploadRequest() .withArn(upload.getArn()); GetUploadResult describeUploadResult = api.getUpload(describeUploadRequest); String status = describeUploadResult.getUpload().getStatus(); if ("SUCCEEDED".equalsIgnoreCase(status)) { break; } else if ("FAILED".equalsIgnoreCase(status)) { throw new DeviceFarmException(String.format("Upload %s failed!", upload.getName())); } else { try { writeToLog(String.format("Waiting for upload %s to be ready (current status: %s)", file.getName(), status)); Thread.sleep(5000); } catch (InterruptedException e) { break; } } } } private void writeToLog(final String msg) { logger.info(msg); } }