/** * Copyright 2014-2017 Linagora, Université Joseph Fourier, Floralis * * The present code is developed in the scope of the joint LINAGORA - * Université Joseph Fourier - Floralis research program and is designated * as a "Result" pursuant to the terms and conditions of the LINAGORA * - Université Joseph Fourier - Floralis research program. Each copyright * holder of Results enumerated here above fully & independently holds complete * ownership of the complete Intellectual Property rights applicable to the whole * of said Results, and may freely exploit it in any manner which does not infringe * the moral rights of the other copyright holders. * * 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 net.roboconf.core.internal.tests; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.logging.Handler; import java.util.logging.LogRecord; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipOutputStream; import org.junit.Assert; import net.roboconf.core.dsl.ParsingModelIoTest; import net.roboconf.core.utils.Utils; /** * @author Vincent Zurczak - Linagora */ public class TestUtils { /** * @return true if the current OS is part of the Linux systems */ public static boolean isUnix() { String os = System.getProperty("os.name").toLowerCase(); return os.contains( "nix" ) || os.contains( "nux" ) || os.contains( "aix" ) || os.contains( "freebsd" ); } /** * @return true if the current OS is part of the Windows systems */ public static boolean isWindows() { String os = System.getProperty("os.name").toLowerCase(); return os.contains( "win" ); } /** * Finds test files. * @param dirName must start with '/' * @return a non-null list * @throws IOException * @throws URISyntaxException */ public static List<File> findTestFiles( String dirName ) throws IOException, URISyntaxException { URL url = ParsingModelIoTest.class.getResource( dirName ); File dir = new File( url.toURI()); if( ! dir.exists()) throw new IOException( "Could not resolve the resource directory." ); File[] resources = dir.listFiles(); if( resources == null ) throw new IOException( "Could not list the resource files." ); return Arrays.asList( resources ); } /** * Finds a test file. * @param fileName must start with '/' * @return an existing file (never null) * @throws IOException * @throws URISyntaxException */ public static File findTestFile( String fileName ) throws IOException, URISyntaxException { return findTestFile( fileName, ParsingModelIoTest.class ); } /** * Finds the location of an application directory located in the "roboconf-core" module. * @param currentDirectory the current directory (generally, <code>new File( "." );</code>). * @param appName the application's name (not null) * @return a non-null file (that may not exist */ public static File findApplicationDirectory( String appName ) throws IOException { // This method must support test execution from Maven and IDE (e.g. Eclipse). String suffix = "core/roboconf-core/src/test/resources/applications/" + appName; File result = new File( "../../" + suffix ).getCanonicalFile(); return result; } /** * Finds a test file. * @param fileName must start with '/' * @param clazz a class to search the class path * @return an existing file (never null) * @throws IOException * @throws URISyntaxException */ public static File findTestFile( String fileName, Class<?> clazz ) throws IOException, URISyntaxException { URL url = clazz.getResource( fileName ); File file; if( url == null || ! (file = new File( url.toURI())).exists()) throw new IOException( "Could not find the resource file." ); return file; } /** * Gets the content of an URI. * @param uri an URI * @return the content available at this address * @throws IOException if something went wrong */ public static String readUriContent( URI uri ) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); InputStream in = null; try { in = uri.toURL().openStream(); Utils.copyStreamSafely( in, out ); } catch( Exception e ) { // nothing } return out.toString( "UTF-8" ); } /** * @return a non-null map associated a ZIP entry name with its text content */ public static Map<String,String> buildZipContent() { Map<String,String> entryToContent = new LinkedHashMap<> (); entryToContent.put( "readme.txt", "This is a readme file." ); entryToContent.put( "graph/main.graph", "import facets.graph;\nimport components.graph;" ); entryToContent.put( "graph/facets.graph", "# nothing yet" ); entryToContent.put( "graph/components.graph", "# nothing here too" ); entryToContent.put( "descriptor/application-descriptor.properties", "application-name = Unit Test" ); entryToContent.put( "instances/initial-deployment.instances", "# No instance" ); entryToContent.put( "some/very/low/folder/demo.txt", "Whatever..." ); entryToContent.put( "graph/", null ); entryToContent.put( "anotherdir/", null ); entryToContent.put( "anotherdir/deeper/", null ); return entryToContent; } /** * Creates a ZIP file from the map. * @param entryToContent a map (key = ZIP entry, value = entry content, null for a directory) * @param targetZipFile */ public static void createZipFile( Map<String,String> entryToContent, File targetZipFile ) throws IOException { ZipOutputStream zos = null; try { zos = new ZipOutputStream( new FileOutputStream( targetZipFile )); for( Map.Entry<String,String> entry : entryToContent.entrySet()) { zos.putNextEntry( new ZipEntry( entry.getKey())); if( entry.getValue() != null ) { ByteArrayInputStream is = new ByteArrayInputStream( entry.getValue().getBytes( "UTF-8" )); try { Utils.copyStreamUnsafelyUseWithCaution( is, zos ); } finally { Utils.closeQuietly( is ); } } zos.closeEntry(); } } finally { Utils.closeQuietly( zos ); } } /** * Compares an assumed ZIP file with a content described in a map. * @param zipFile * @param entryToContent * @throws ZipException * @throws IOException */ public static void compareZipContent( File zipFile, Map<String,String> entryToContent ) throws IOException { File tempDir = new File( System.getProperty( "java.io.tmpdir" ), UUID.randomUUID().toString()); if( ! tempDir.mkdir()) Assert.fail( "Failed to create a temporary directory." ); try { Utils.extractZipArchive( zipFile, tempDir ); compareUnzippedContent( tempDir, entryToContent ); } finally { Utils.deleteFilesRecursively( tempDir ); } } /** * Compares an assumed ZIP file with a content described in a map. * @param rootDirectory the root directory of the unzipped content * @param entryToContent the map associating entries and content (null for directories) * @throws IOException */ public static void compareUnzippedContent( File rootDirectory, Map<String,String> entryToContent ) throws IOException { for( Map.Entry<String,String> entry : entryToContent.entrySet()) { File extractedFile = new File( rootDirectory, entry.getKey()); Assert.assertTrue( "Missing entry: " + entry.getKey(), extractedFile.exists()); if( entry.getValue() == null ) { Assert.assertTrue( entry.getKey() + " was supposed to be a directory.", extractedFile.isDirectory()); continue; } Assert.assertTrue( entry.getKey() + " was supposed to be a file.", extractedFile.isFile()); String fileContent = Utils.readFileContent( extractedFile ); Assert.assertEquals( entry.getValue(), fileContent ); } } /** * Gets the value of an internal field. * <p> * It is sometimes useful during tests to access a field that should remain * private in a normal execution. This method requires permissions to access * private fields. * </p> * <p> * Super class are searched too. * </p> * * @param o the object from which the field must be retrieved * @param fieldName the field name * @param clazz the class of the internal field * @return the internal field's value or null if this field was not found * @throws IllegalAccessException if the field could not be read */ public static <T> T getInternalField( Object o, String fieldName, Class<T> clazz ) throws IllegalAccessException { Object fieldValue = null; for( Class<?> c = o.getClass(); c != null && fieldValue == null; c = c.getSuperclass()) { try { Field field = c.getDeclaredField( fieldName ); field.setAccessible( true ); fieldValue = field.get( o ); } catch( NoSuchFieldException e ) { // nothing } } return clazz.cast( fieldValue ); } /** * A log handler that writes records in a string buffer. * @author Vincent Zurczak - Linagora */ public static class StringHandler extends Handler { private final StringBuilder sb = new StringBuilder(); @Override public void close() throws SecurityException { // nothing } @Override public void flush() { // nothing } @Override public void publish( LogRecord rec ) { this.sb.append( rec.getMessage() + "\n" ); } public String getLogs() { return this.sb.toString(); } public StringBuilder getStringBuilder() { return this.sb; } } }