/* * Copyright 2015 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.fail; import static org.mockito.Mockito.when; import hudson.model.AbstractBuild; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Set; import java.util.zip.CRC32; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; import org.apache.commons.io.FileUtils; import org.apache.tools.zip.ZipOutputStream; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.model.InitializationError; import org.junit.runners.model.RunnerBuilder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import com.amazonaws.codepipeline.jenkinsplugin.CodePipelineStateModel.CompressionType; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.S3Object; @RunWith(ExtractionToolsTest.class) @Suite.SuiteClasses({ ExtractionToolsTest.GetCompressionTypeTest.class, ExtractionToolsTest.DecompressFileTest.class }) public class ExtractionToolsTest extends Suite { private static final String FILE_PATH = Paths.get("A", "File").toString(); public ExtractionToolsTest(final Class<?> klass, final RunnerBuilder builder) throws InitializationError { super(klass, builder); } private static class TestBase { public void setUp() throws IOException { MockitoAnnotations.initMocks(this); TestUtils.initializeTestingFolders(); } public void tearDown() throws IOException { TestUtils.cleanUpTestingFolders(); } } public static class GetCompressionTypeTest extends TestBase { private CodePipelineStateModel model; @Mock private S3Object obj; @Mock private AbstractBuild<?, ?> mockBuild; @Mock private ObjectMetadata metadata; @Before public void setUp() throws IOException { super.setUp(); model = new CodePipelineStateModel(); model.setCompressionType(CompressionType.None); when(obj.getObjectMetadata()).thenReturn(metadata); } @After public void tearDown() throws IOException { super.tearDown(); } @Test public void getCompressionTypeZipSuccess() { when(obj.getKey()).thenReturn(Paths.get(FILE_PATH, "Yes.zip").toString()); final CompressionType compressionType = ExtractionTools.getCompressionType(obj, null); assertEquals(CompressionType.Zip, compressionType); } @Test public void getCompressionTypeTarSuccess() { when(obj.getKey()).thenReturn(Paths.get(FILE_PATH, "Yes.tar").toString()); final CompressionType compressionType = ExtractionTools.getCompressionType(obj, null); assertEquals(CompressionType.Tar, compressionType); } @Test public void getCompressionTypeTarGzSuccess() { when(obj.getKey()).thenReturn(Paths.get(FILE_PATH, "Yes.tar.gz").toString()); final CompressionType compressionType = ExtractionTools.getCompressionType(obj, null); assertEquals(CompressionType.TarGz, compressionType); } @Test public void noCompressionTypeFoundNullFailure() { when(obj.getKey()).thenReturn(Paths.get(FILE_PATH, "Yes.notanextension").toString()); when(metadata.getContentType()).thenReturn("notanextension"); final CompressionType compressionType = ExtractionTools.getCompressionType(obj, null); assertEquals(CompressionType.None, compressionType); } @Test public void getCompressionTypeZipFromMetadataSuccess() { when(obj.getKey()).thenReturn("A" + File.separator + "File" + File.separator + "XK321K"); when(metadata.getContentType()).thenReturn("application/zip"); final CompressionType compressionType = ExtractionTools.getCompressionType(obj, null); assertEquals(CompressionType.Zip, compressionType); } @Test public void getCompressionTypeTarFromMetadataSuccess() { when(obj.getKey()).thenReturn("A" + File.separator + "File" + File.separator + "XK321K"); when(metadata.getContentType()).thenReturn("application/tar"); final CompressionType compressionType = ExtractionTools.getCompressionType(obj, null); assertEquals(CompressionType.Tar, compressionType); } @Test public void getCompressionTypeTarGzFromMetadataSuccess() { when(obj.getKey()).thenReturn("A" + File.separator + "File" + File.separator + "XK321K"); when(metadata.getContentType()).thenReturn("application/gzip"); final CompressionType compressionType = ExtractionTools.getCompressionType(obj, null); assertEquals(CompressionType.TarGz, compressionType); } @Test public void getCompressionTypeTarGzXFromMetadataSuccess() { when(obj.getKey()).thenReturn("A" + File.separator + "File" + File.separator + "XK321K"); when(metadata.getContentType()).thenReturn("application/x-gzip"); final CompressionType compressionType = ExtractionTools.getCompressionType(obj, null); assertEquals(CompressionType.TarGz, compressionType); } @Test public void getCompressionTypeTarXFromMetadataSuccess() { when(obj.getKey()).thenReturn("A" + File.separator + "File" + File.separator + "XK321K"); when(metadata.getContentType()).thenReturn("application/x-tar"); final CompressionType compressionType = ExtractionTools.getCompressionType(obj, null); assertEquals(CompressionType.Tar, compressionType); } } public static class DecompressFileTest extends TestBase { private static final String ARCHIVE_PREFIX = "decompress-test"; private Path testDir; private Path compressedFile; private Path decompressDestination; @Before public void setUp() throws IOException { super.setUp(); testDir = Paths.get(TestUtils.TEST_DIR); decompressDestination = Files.createTempDirectory(ARCHIVE_PREFIX); try (final PrintWriter writer = new PrintWriter( Paths.get(TestUtils.TEST_DIR, "bbb.txt").toFile())) { writer.println("Some test data for the file"); } } @After public void tearDown() throws IOException { super.tearDown(); Files.deleteIfExists(compressedFile); FileUtils.deleteDirectory(decompressDestination.toFile()); } @Test public void canDecompressZipFile() { try { compressedFile = Files.createTempFile(ARCHIVE_PREFIX, ".zip"); try (final ZipArchiveOutputStream outputStream = new ZipArchiveOutputStream( new BufferedOutputStream(new FileOutputStream(compressedFile.toFile())))) { // Deflated is the default compression method zipDirectory(testDir, outputStream, ZipOutputStream.DEFLATED); } ExtractionTools.decompressFile( compressedFile.toFile(), decompressDestination.toFile(), CompressionType.Zip, null); assertEquals(getFileNames(testDir), getFileNames(decompressDestination)); } catch (final IOException e) { fail(e.getMessage()); } } @Test public void canDecompressZipFileWithStoredCompressionMethod() { try { compressedFile = Files.createTempFile(ARCHIVE_PREFIX, ".zip"); try (final ZipArchiveOutputStream outputStream = new ZipArchiveOutputStream( new BufferedOutputStream(new FileOutputStream(compressedFile.toFile())))) { zipDirectory(testDir, outputStream, ZipOutputStream.STORED); } ExtractionTools.decompressFile( compressedFile.toFile(), decompressDestination.toFile(), CompressionType.Zip, null); assertEquals(getFileNames(testDir), getFileNames(decompressDestination)); } catch (final IOException e) { fail(e.getMessage()); } } // e.g.: zip -r --exclude *.git* - . | aws s3 cp - s3://code-pipeline/aws-codedeploy-demo.zip @Test public void canDecompressZipFileCreatedFromCommandLine() { try { compressedFile = Paths.get(getClass().getClassLoader().getResource("aws-codedeploy-demo.zip").getFile()); ExtractionTools.decompressFile( compressedFile.toFile(), decompressDestination.toFile(), CompressionType.Zip, null); final Set<String> files = new HashSet<>(Arrays.asList(".DS_Store", "appspec.yml", "aws-codepipeline-jenkins-aws-codedeploy_linux.zip", "Gemfile", "LICENSE", "Rakefile", "README.md", "install_dependencies", "start_server", "stop_server", "index.html.haml", "jenkins_sample_test.rb")); assertEquals(files, getFileNames(decompressDestination)); } catch (final IOException e) { fail(e.getMessage()); } } @SuppressWarnings("unchecked") private static Set<String> getFileNames(final Path dir) { final Collection<File> files = FileUtils.listFiles(dir.toFile(), null, true); final Set<String> fileNames = new HashSet<>(); for (final File file : files) { fileNames.add(file.getName()); } return fileNames; } private static void zipDirectory( final Path directory, final ZipArchiveOutputStream out, final int compressionMethod) throws IOException { Files.walkFileTree(directory, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { final String entryName = directory.relativize(file).toString(); final ZipArchiveEntry archiveEntry = new ZipArchiveEntry(file.toFile(), entryName); final byte[] contents = Files.readAllBytes(file); out.setMethod(compressionMethod); archiveEntry.setMethod(compressionMethod); if (compressionMethod == ZipOutputStream.STORED) { archiveEntry.setSize(contents.length); final CRC32 crc32 = new CRC32(); crc32.update(contents); archiveEntry.setCrc(crc32.getValue()); } out.putArchiveEntry(archiveEntry); out.write(contents); out.closeArchiveEntry(); return FileVisitResult.CONTINUE; } }); } } }