/* * 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.assertFalse; 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.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.FileInputStream; import java.io.IOException; 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.S3Object; import com.amazonaws.services.s3.model.S3ObjectInputStream; public class DownloadCallableTest { 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.zip"; private static final boolean CLEAR_WORKSPACE = true; @Mock private AWSClientFactory clientFactory; @Mock private AWSClients awsClients; @Mock private AWSCodePipeline codePipelineClient; @Mock private AmazonS3 s3Client; @Mock private S3Object s3Object; @Mock private Job job; @Mock private JobData jobData; @Mock private GetJobDetailsResult getJobDetailsResult; @Mock private JobDetails jobDetails; @Mock private JobData getJobDetailsJobData; @Mock private Artifact inputArtifact; @Mock private ArtifactLocation artifactLocation; @Mock private CodePipelineStateModel model; @Captor private ArgumentCaptor<GetJobDetailsRequest> getJobDetailsRequestCaptor; @Captor private ArgumentCaptor<AWSCredentialsProvider> credentialsProviderCaptor; private File workspace; private ByteArrayOutputStream outContent; private List<Artifact> inputArtifacts; private S3ArtifactLocation s3ArtifactLocation; private S3ObjectInputStream s3ObjectInputStream; private DownloadCallable downloader; @Before public void setUp() throws IOException { MockitoAnnotations.initMocks(this); TestUtils.initializeTestingFolders(); workspace = Paths.get(TestUtils.TEST_DIR).toFile(); outContent = TestUtils.setOutputStream(); inputArtifacts = new ArrayList<>(); inputArtifacts.add(inputArtifact); s3ArtifactLocation = new S3ArtifactLocation(); s3ArtifactLocation.setBucketName(S3_BUCKET_NAME); s3ArtifactLocation.setObjectKey(S3_OBJECT_KEY); s3ObjectInputStream = new S3ObjectInputStream( new FileInputStream(getClass().getClassLoader().getResource("aws-codedeploy-demo.zip").getFile()), null, false); 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(s3Client.getObject(anyString(), anyString())).thenReturn(s3Object); when(s3Object.getKey()).thenReturn(S3_OBJECT_KEY); when(s3Object.getObjectContent()).thenReturn(s3ObjectInputStream); when(model.getAwsAccessKey()).thenReturn(ACCESS_KEY); when(model.getAwsSecretKey()).thenReturn(SECRET_KEY); when(model.getProxyHost()).thenReturn(PROXY_HOST); when(model.getProxyPort()).thenReturn(PROXY_PORT); when(model.getRegion()).thenReturn(REGION); when(model.getCompressionType()).thenReturn(CompressionType.Zip); when(job.getId()).thenReturn(JOB_ID); when(job.getData()).thenReturn(jobData); when(jobData.getInputArtifacts()).thenReturn(inputArtifacts); 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(inputArtifact.getLocation()).thenReturn(artifactLocation); when(artifactLocation.getS3Location()).thenReturn(s3ArtifactLocation); downloader = new DownloadCallable(CLEAR_WORKSPACE, job, model, clientFactory, PLUGIN_VERSION, null); } @After public void tearDown() throws IOException { TestUtils.cleanUpTestingFolders(); s3ObjectInputStream.close(); } @Test public void getsArtifactFromS3() throws InterruptedException { // when downloader.invoke(workspace, null); // then final InOrder inOrder = inOrder(clientFactory, awsClients, s3Client, model); 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).getObject(S3_BUCKET_NAME, S3_OBJECT_KEY); inOrder.verify(model).setCompressionType(CompressionType.Zip); 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()); } @Test public void clearsWorkspace() throws InterruptedException { // given downloader = new DownloadCallable(true, job, model, clientFactory, PLUGIN_VERSION, null); // when downloader.invoke(workspace, null); // then assertFalse(doesWorkspaceFileExist("Dir1")); assertFalse(doesWorkspaceFileExist("bbb.txt")); assertContainsIgnoreCase("[AWS CodePipeline Plugin] Clearing workspace", outContent.toString()); } @Test public void doesNotClearWorkspace() throws InterruptedException { // given downloader = new DownloadCallable(false, job, model, clientFactory, PLUGIN_VERSION, null); // when downloader.invoke(workspace, null); // then assertTrue(doesWorkspaceFileExist("Dir1")); assertTrue(doesWorkspaceFileExist("bbb.txt")); assertFalse(outContent.toString().toLowerCase().contains("[AWS CodePipeline Plugin] Clearing workspace".toLowerCase())); } @Test public void downloadsAndExtractsInputArchive() throws InterruptedException { // when downloader.invoke(workspace, null); // then verify(model).setCompressionType(CompressionType.Zip); assertTrue(doesWorkspaceFileExist("appspec.yml")); assertTrue(doesWorkspaceFileExist("src", "index.html.haml")); assertContainsIgnoreCase("[AWS CodePipeline Plugin] Successfully downloaded artifact from AWS CodePipeline", outContent.toString()); assertContainsIgnoreCase("[AWS CodePipeline Plugin] Extracting", outContent.toString()); assertContainsIgnoreCase("[AWS CodePipeline Plugin] Artifact uncompressed successfully", outContent.toString()); } private boolean doesWorkspaceFileExist(final String... path) { return Paths.get(TestUtils.TEST_DIR, path).toFile().exists(); } }