/*
* Copyright © 2015 Cask Data, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 co.cask.cdap.internal.app.runtime;
import co.cask.cdap.common.io.Locations;
import co.cask.cdap.common.lang.jar.BundleJarUtil;
import co.cask.cdap.internal.app.runtime.distributed.LocalizeResource;
import com.google.common.base.Charsets;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockftpserver.fake.FakeFtpServer;
import org.mockftpserver.fake.UserAccount;
import org.mockftpserver.fake.filesystem.FileEntry;
import org.mockftpserver.fake.filesystem.FileSystem;
import org.mockftpserver.fake.filesystem.UnixFakeFileSystem;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.zip.GZIPOutputStream;
/**
* Tests for {@link LocalizationUtils}.
*/
public class LocalizationUtilsTest {
@ClassRule
public static final TemporaryFolder TEMP_FOLDER = new TemporaryFolder();
@Test
public void testRemoteFile() throws IOException {
File directory = TEMP_FOLDER.newFolder("ftp");
File ftpFile = new File(directory, "ftp_file");
String ftpFileContents = "Contents of ftp_file";
FileSystem fileSystem = new UnixFakeFileSystem();
fileSystem.add(new FileEntry(ftpFile.getAbsolutePath(), ftpFileContents));
String user = "user";
String password = "password";
FakeFtpServer ftpServer = new FakeFtpServer();
// Use any available port
ftpServer.setServerControlPort(0);
ftpServer.addUserAccount(new UserAccount(user, password, directory.getAbsolutePath()));
ftpServer.setFileSystem(fileSystem);
ftpServer.start();
try {
URI uri = URI.create(String.format("ftp://%s:%s@localhost:%d/%s", user, password,
ftpServer.getServerControlPort(), ftpFile.getName()));
File localizationDir = TEMP_FOLDER.newFolder("localRemote");
File localizedResource = LocalizationUtils.localizeResource("file1", new LocalizeResource(uri, false),
localizationDir);
Assert.assertTrue(localizedResource.exists());
Assert.assertTrue(localizedResource.isFile());
Assert.assertEquals(ftpFileContents, com.google.common.io.Files.toString(localizedResource, Charsets.UTF_8));
} finally {
ftpServer.stop();
}
}
@Test
public void testZip() throws IOException {
String zipFileName = "target";
File directory = TEMP_FOLDER.newFolder("zip");
File file1 = File.createTempFile("file1", ".txt", directory);
File file2 = File.createTempFile("file2", ".txt", directory);
File zipFile = createZipFile(zipFileName, directory, false);
File localizationDir = TEMP_FOLDER.newFolder("localZip");
File localizedResource = LocalizationUtils.localizeResource(zipFileName, new LocalizeResource(zipFile, true),
localizationDir);
Assert.assertTrue(localizedResource.isDirectory());
File[] files = localizedResource.listFiles();
Assert.assertNotNull(files);
Assert.assertEquals(2, files.length);
if (file1.getName().equals(files[0].getName())) {
Assert.assertEquals(file2.getName(), files[1].getName());
} else {
Assert.assertEquals(file1.getName(), files[1].getName());
Assert.assertEquals(file2.getName(), files[0].getName());
}
}
@Test
public void testJar() throws IOException {
String jarFileName = "target";
File directory = TEMP_FOLDER.newFolder("jar");
File libDir = new File(directory, "lib");
Assert.assertTrue(libDir.mkdirs());
File someClassFile = File.createTempFile("SomeClass", ".class", directory);
File someOtherClassFile = File.createTempFile("SomeOtherClass", ".class", directory);
File jarFile = createZipFile(jarFileName, directory, true);
File localizationDir = TEMP_FOLDER.newFolder("localJar");
File localizedResource = LocalizationUtils.localizeResource(jarFileName, new LocalizeResource(jarFile, true),
localizationDir);
Assert.assertTrue(localizedResource.isDirectory());
File[] files = localizedResource.listFiles();
Assert.assertNotNull(files);
Assert.assertEquals(3, files.length);
for (File file : files) {
String name = file.getName();
if (libDir.getName().equals(name)) {
Assert.assertTrue(file.isDirectory());
} else {
Assert.assertTrue(someClassFile.getName().equals(name) || someOtherClassFile.getName().equals(name));
}
}
}
@Test
public void testTar() throws IOException {
testTarFiles(TarFileType.TAR);
}
@Test
public void testTarGz() throws IOException {
testTarFiles(TarFileType.TAR_GZ);
}
@Test
public void testTgz() throws IOException {
testTarFiles(TarFileType.TGZ);
}
@Test(expected = IllegalArgumentException.class)
public void testGz() throws IOException {
String gzFileName = "target";
File directory = TEMP_FOLDER.newFolder("gz");
File source = File.createTempFile("source", ".txt", directory);
File gzFile = createGzFile(gzFileName, source);
File localizationDir = TEMP_FOLDER.newFolder("localGz");
LocalizationUtils.localizeResource(gzFileName, new LocalizeResource(gzFile, true), localizationDir);
}
private void testTarFiles(TarFileType type) throws IOException {
String tarFileName = "target";
// Have to use short file/directory names because TarArchiveOutputStream does not like long paths.
File directory;
File localizationDir;
switch (type) {
case TAR:
directory = TEMP_FOLDER.newFolder("t1");
localizationDir = TEMP_FOLDER.newFolder("localTar");
break;
case TAR_GZ:
directory = TEMP_FOLDER.newFolder("t2");
localizationDir = TEMP_FOLDER.newFolder("localTarGz");
break;
case TGZ:
directory = TEMP_FOLDER.newFolder("t3");
localizationDir = TEMP_FOLDER.newFolder("localTgz");
break;
default:
throw new IllegalArgumentException("Unexpected type: " + type);
}
File file1 = new File(Files.createFile(Paths.get(new File(directory, "f1").toURI())).toUri());
File file2 = new File(Files.createFile(Paths.get(new File(directory, "f2").toURI())).toUri());
File tarFile;
switch (type) {
case TAR:
tarFile = createTarFile(tarFileName, file1, file2);
break;
case TAR_GZ:
tarFile = createTarGzFile(tarFileName, file1, file2);
break;
case TGZ:
tarFile = createTgzFile(tarFileName, file1, file2);
break;
default:
throw new IllegalArgumentException("Unexpected type: " + type);
}
File localizedResource = LocalizationUtils.localizeResource(tarFileName, new LocalizeResource(tarFile, true),
localizationDir);
Assert.assertTrue(localizedResource.isDirectory());
File[] files = localizedResource.listFiles();
Assert.assertNotNull(files);
Assert.assertEquals(2, files.length);
for (File file : files) {
String name = file.getName();
Assert.assertTrue(file1.getName().equals(name) || file2.getName().equals(name));
}
}
private File createZipFile(String zipFileName, File dirToJar, boolean isJar) throws IOException {
String extension = isJar ? ".jar" : ".zip";
File target = TEMP_FOLDER.newFile(zipFileName + extension);
BundleJarUtil.createJar(dirToJar, target);
File[] files = dirToJar.listFiles();
Assert.assertNotNull(files);
for (File file : files) {
if (!file.isDirectory()) {
BundleJarUtil.getEntry(Locations.toLocation(target), file.getName()).getInput().close();
}
}
return target;
}
private File createTarFile(String tarFileName, File ... filesToAdd) throws IOException {
File target = TEMP_FOLDER.newFile(tarFileName + ".tar");
try (TarArchiveOutputStream tos =
new TarArchiveOutputStream(new BufferedOutputStream(new FileOutputStream(target)))) {
addFilesToTar(tos, filesToAdd);
}
return target;
}
private File createTgzFile(String tgzFileName, File ... filesToAdd) throws IOException {
File target = TEMP_FOLDER.newFile(tgzFileName + ".tgz");
try (TarArchiveOutputStream tos =
new TarArchiveOutputStream(new GZIPOutputStream(new BufferedOutputStream(new FileOutputStream(target))))) {
addFilesToTar(tos, filesToAdd);
}
return target;
}
private File createTarGzFile(String tarGzFileName, File ... filesToAdd) throws IOException {
File target = TEMP_FOLDER.newFile(tarGzFileName + ".tar.gz");
try (TarArchiveOutputStream tos =
new TarArchiveOutputStream(new GZIPOutputStream(new BufferedOutputStream(new FileOutputStream(target))))) {
addFilesToTar(tos, filesToAdd);
}
return target;
}
private void addFilesToTar(TarArchiveOutputStream tos, File ... filesToAdd) throws IOException {
for (File file : filesToAdd) {
TarArchiveEntry tarEntry = new TarArchiveEntry(file);
tos.putArchiveEntry(tarEntry);
if (file.isFile()) {
com.google.common.io.Files.copy(file, tos);
}
tos.closeArchiveEntry();
}
}
private File createGzFile(String gzFileName, File sourceFile) throws IOException {
File target = TEMP_FOLDER.newFile(gzFileName + ".gz");
try (GZIPOutputStream gzos = new GZIPOutputStream(new FileOutputStream(target))) {
com.google.common.io.Files.copy(sourceFile, gzos);
}
return target;
}
private enum TarFileType {
TAR,
TAR_GZ,
TGZ
}
}