/* * Copyright 2016 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.codepipeline.jenkinsplugin; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static com.amazonaws.codepipeline.jenkinsplugin.TestUtils.assertContainsIgnoreCase; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.UUID; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.codepipeline.jenkinsplugin.CodePipelineStateModel.CompressionType; import com.amazonaws.services.codepipeline.AWSCodePipeline; import com.amazonaws.services.codepipeline.model.AWSSessionCredentials; import com.amazonaws.services.codepipeline.model.Artifact; import com.amazonaws.services.codepipeline.model.ArtifactLocation; import com.amazonaws.services.codepipeline.model.GetJobDetailsRequest; import com.amazonaws.services.codepipeline.model.GetJobDetailsResult; import com.amazonaws.services.codepipeline.model.Job; import com.amazonaws.services.codepipeline.model.JobData; import com.amazonaws.services.codepipeline.model.JobDetails; import com.amazonaws.services.codepipeline.model.S3ArtifactLocation; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.model.InitiateMultipartUploadRequest; import com.amazonaws.services.s3.model.InitiateMultipartUploadResult; import com.amazonaws.services.s3.model.PartETag; import com.amazonaws.services.s3.model.UploadPartRequest; import com.amazonaws.services.s3.model.UploadPartResult; public class PublisherCallableTest { private static final String PROJECT_NAME = "Project"; private static final String PLUGIN_VERSION = "aws-codepipeline:0.15"; private static final String ACCESS_KEY = "AKIAIOSFODNN7EXAMPLE"; private static final String SECRET_KEY = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"; private static final String PROXY_HOST = "localhost"; private static final int PROXY_PORT = 80; private static final String REGION = "us-east-1"; private static final String JOB_ID = UUID.randomUUID().toString(); private static final String JOB_ACCESS_KEY = "BPTDIOSFODNN7EXAMPLE"; private static final String JOB_SECRET_KEY = "xKdpsXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"; private static final String JOB_SESSION_TOKEN = "1231"; private static AWSSessionCredentials JOB_CREDENTIALS = new AWSSessionCredentials() .withAccessKeyId(JOB_ACCESS_KEY) .withSecretAccessKey(JOB_SECRET_KEY) .withSessionToken(JOB_SESSION_TOKEN); private static final String S3_BUCKET_NAME = "bucket"; private static final String S3_OBJECT_KEY = "object"; private static final String UPLOAD_ID = "12312"; private static final String TEST_FILE = "bbb.txt"; @Mock private AWSClientFactory clientFactory; @Mock private AWSClients awsClients; @Mock private AWSCodePipeline codePipelineClient; @Mock private AmazonS3 s3Client; @Mock private Job job; @Mock private JobData jobData; @Mock private Artifact outputArtifact; @Mock private ArtifactLocation artifactLocation; @Mock private GetJobDetailsResult getJobDetailsResult; @Mock private JobDetails jobDetails; @Mock private JobData getJobDetailsJobData; @Mock private InitiateMultipartUploadResult initiateMultipartUploadResult; @Mock private UploadPartResult uploadPartResult; @Captor private ArgumentCaptor<GetJobDetailsRequest> getJobDetailsRequestCaptor; @Captor private ArgumentCaptor<AWSCredentialsProvider> credentialsProviderCaptor; @Captor private ArgumentCaptor<InitiateMultipartUploadRequest> initiateMultipartUploadRequestCaptor; @Captor private ArgumentCaptor<UploadPartRequest> uploadPartRequestCaptor; private ByteArrayOutputStream outContent; private CodePipelineStateModel model; private List<OutputArtifact> jenkinsOutputs; private List<Artifact> outputArtifacts; private S3ArtifactLocation s3ArtifactLocation; private File workspace; private PublisherCallable publisher; @Before public void setUp() throws IOException { MockitoAnnotations.initMocks(this); TestUtils.initializeTestingFolders(); workspace = Paths.get(TestUtils.TEST_DIR).toFile(); outContent = TestUtils.setOutputStream(); try (final PrintWriter writer = new PrintWriter(new File(workspace, TEST_FILE))) { writer.println("Some content"); } model = new CodePipelineStateModel(); model.setJob(job); model.setCompressionType(CompressionType.Zip); model.setAwsAccessKey(ACCESS_KEY); model.setAwsSecretKey(SECRET_KEY); model.setProxyHost(PROXY_HOST); model.setProxyPort(PROXY_PORT); model.setRegion(REGION); jenkinsOutputs = new ArrayList<>(); jenkinsOutputs.add(new OutputArtifact("")); outputArtifacts = new ArrayList<>(); outputArtifacts.add(outputArtifact); s3ArtifactLocation = new S3ArtifactLocation(); s3ArtifactLocation.setBucketName(S3_BUCKET_NAME); s3ArtifactLocation.setObjectKey(S3_OBJECT_KEY); when(clientFactory.getAwsClient(anyString(), anyString(), anyString(), anyInt(), anyString(), anyString())).thenReturn(awsClients); when(awsClients.getCodePipelineClient()).thenReturn(codePipelineClient); when(awsClients.getS3Client(any(AWSCredentialsProvider.class))).thenReturn(s3Client); when(job.getId()).thenReturn(JOB_ID); when(job.getData()).thenReturn(jobData); when(jobData.getOutputArtifacts()).thenReturn(outputArtifacts); when(codePipelineClient.getJobDetails(any(GetJobDetailsRequest.class))).thenReturn(getJobDetailsResult); when(getJobDetailsResult.getJobDetails()).thenReturn(jobDetails); when(jobDetails.getData()).thenReturn(getJobDetailsJobData); when(getJobDetailsJobData.getArtifactCredentials()).thenReturn(JOB_CREDENTIALS); when(outputArtifact.getLocation()).thenReturn(artifactLocation); when(artifactLocation.getS3Location()).thenReturn(s3ArtifactLocation); when(s3Client.initiateMultipartUpload(any(InitiateMultipartUploadRequest.class))).thenReturn(initiateMultipartUploadResult); when(initiateMultipartUploadResult.getUploadId()).thenReturn(UPLOAD_ID); when(s3Client.uploadPart(any(UploadPartRequest.class))).thenReturn(uploadPartResult); when(uploadPartResult.getPartETag()).thenReturn(new PartETag(1, "asdf")); publisher = new PublisherCallable(PROJECT_NAME, model, jenkinsOutputs, clientFactory, PLUGIN_VERSION, null); } @After public void tearDown() throws IOException { TestUtils.cleanUpTestingFolders(); } @Test public void uploadsArtifactToS3() throws IOException { // when publisher.invoke(workspace, null); // then final InOrder inOrder = inOrder(clientFactory, awsClients, s3Client); inOrder.verify(clientFactory).getAwsClient(ACCESS_KEY, SECRET_KEY, PROXY_HOST, PROXY_PORT, REGION, PLUGIN_VERSION); inOrder.verify(awsClients).getCodePipelineClient(); inOrder.verify(awsClients).getS3Client(credentialsProviderCaptor.capture()); inOrder.verify(s3Client).initiateMultipartUpload(initiateMultipartUploadRequestCaptor.capture()); inOrder.verify(s3Client).uploadPart(uploadPartRequestCaptor.capture()); final com.amazonaws.auth.AWSSessionCredentials credentials = (com.amazonaws.auth.AWSSessionCredentials) credentialsProviderCaptor.getValue().getCredentials(); assertEquals(JOB_ACCESS_KEY, credentials.getAWSAccessKeyId()); assertEquals(JOB_SECRET_KEY, credentials.getAWSSecretKey()); assertEquals(JOB_SESSION_TOKEN, credentials.getSessionToken()); verify(codePipelineClient).getJobDetails(getJobDetailsRequestCaptor.capture()); assertEquals(JOB_ID, getJobDetailsRequestCaptor.getValue().getJobId()); final InitiateMultipartUploadRequest initRequest = initiateMultipartUploadRequestCaptor.getValue(); assertEquals(S3_BUCKET_NAME, initRequest.getBucketName()); assertEquals(S3_OBJECT_KEY, initRequest.getKey()); final UploadPartRequest uploadRequest = uploadPartRequestCaptor.getValue(); assertEquals(S3_BUCKET_NAME, uploadRequest.getBucketName()); assertEquals(S3_OBJECT_KEY, uploadRequest.getKey()); assertEquals(UPLOAD_ID, uploadRequest.getUploadId()); assertContainsIgnoreCase("[AWS CodePipeline Plugin] Uploading artifact:", outContent.toString()); assertContainsIgnoreCase("[AWS CodePipeline Plugin] Upload successful\n", outContent.toString()); } @Test public void forDirectoriesUsesZipAsDefaultCompressionType() throws IOException { // given model.setCompressionType(CompressionType.None); // when publisher.invoke(workspace, null); // then verify(s3Client).initiateMultipartUpload(initiateMultipartUploadRequestCaptor.capture()); verify(s3Client).uploadPart(uploadPartRequestCaptor.capture()); assertEquals("application/zip", initiateMultipartUploadRequestCaptor.getValue().getObjectMetadata().getContentType()); assertTrue(uploadPartRequestCaptor.getValue().getFile().getName().endsWith(".zip")); } @Test public void forDirecotriesUsesCompressionTypeSpecifiedInModel() throws IOException { // given model.setCompressionType(CompressionType.Tar); // when publisher.invoke(workspace, null); // then verify(s3Client).initiateMultipartUpload(initiateMultipartUploadRequestCaptor.capture()); verify(s3Client).uploadPart(uploadPartRequestCaptor.capture()); assertEquals("application/tar", initiateMultipartUploadRequestCaptor.getValue().getObjectMetadata().getContentType()); assertTrue(uploadPartRequestCaptor.getValue().getFile().getName().endsWith(".tar")); } @Test public void doesNotUseCompressionWhenUploadingNormalFiles() throws IOException { // given jenkinsOutputs.clear(); jenkinsOutputs.add(new OutputArtifact("bbb.txt")); // when publisher.invoke(workspace, null); // then verify(s3Client).initiateMultipartUpload(initiateMultipartUploadRequestCaptor.capture()); verify(s3Client).uploadPart(uploadPartRequestCaptor.capture()); assertNull(initiateMultipartUploadRequestCaptor.getValue().getObjectMetadata().getContentType()); assertEquals("bbb.txt", uploadPartRequestCaptor.getValue().getFile().getName()); } @Test public void canUploadMultipleOutputArtifacts() throws IOException { // given jenkinsOutputs.clear(); jenkinsOutputs.add(new OutputArtifact(TEST_FILE)); jenkinsOutputs.add(new OutputArtifact("Dir1")); jenkinsOutputs.add(new OutputArtifact("Dir2")); outputArtifacts.clear(); outputArtifacts.add(outputArtifact); outputArtifacts.add(outputArtifact); outputArtifacts.add(outputArtifact); // when publisher.invoke(workspace, null); // then verify(s3Client, times(3)).initiateMultipartUpload(any(InitiateMultipartUploadRequest.class)); } }