/*
* ******************************************************************************
*
* Copyright (C) 2002-2016 by Pentaho : http://www.pentaho.com
*
* ******************************************************************************
*
* 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 org.pentaho.platform.osgi;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.osgi.framework.Constants;
import org.pentaho.di.core.KettleClientEnvironment;
import org.pentaho.platform.api.engine.IApplicationContext;
import org.pentaho.platform.api.engine.IPentahoSession;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.engine.core.system.StandaloneApplicationContext;
import org.pentaho.test.platform.utils.TestResourceLocation;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileAttribute;
import java.util.Locale;
import java.util.Properties;
import static org.junit.Assert.*;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.*;
/**
* Created by rfellows on 10/23/15.
*/
@RunWith( MockitoJUnitRunner.class )
public class KarafBootTest {
private static File configProps;
KarafBoot boot;
@Mock IApplicationContext appContext;
@Mock IPentahoSession session;
@Mock KarafInstance karafInstance;
static File tmpDir;
@BeforeClass
public static void init() throws Exception {
Properties props = new Properties();
props.setProperty( Constants.FRAMEWORK_BEGINNING_STARTLEVEL, "100" );
props.setProperty( "karaf.framework", "felix" );
Path karafBootTest = Files.createTempDirectory( "KarafBootTest", new FileAttribute[ 0 ] );
tmpDir = karafBootTest.toFile();
configProps = new File( tmpDir, "system/karaf/etc/config.properties" );
configProps.getParentFile().mkdirs();
new File( tmpDir, "system/karaf/system" ).mkdirs();
new File( tmpDir, "system/karaf/caches" ).mkdirs();
try ( FileOutputStream fileOutputStream = new FileOutputStream( configProps ) ) {
props.store( fileOutputStream, "Minimal properties for test KarafBoot without issue" );
}
}
@AfterClass
public static void cleanUp() throws IOException {
if ( tmpDir.exists() ) {
tmpDir.deleteOnExit();
}
}
@Before
public void setUp() throws Exception {
PentahoSystem.setApplicationContext( appContext );
when( appContext.getSolutionRootPath() ).thenReturn( tmpDir.getPath() );
boot = new KarafBoot();
}
@After
public void tearDown() throws Exception {
PentahoSystem.clearObjectFactory();
boot.shutdown();
}
@Test
public void testStartup_noKarafPortsYaml() throws Exception {
KarafBoot karafBoot = spy( boot );
doReturn( karafInstance ).when( karafBoot ).createAndProcessKarafInstance( anyString() );
assertFalse( karafBoot.startup( session ) );
}
@Test
public void testStartup() throws Exception {
String origKarafHome = System.getProperty( "karaf.home" );
try {
System.getProperties().remove( "karaf.home" );
KarafBoot karafBoot = spy( boot );
doReturn( karafInstance ).when( karafBoot ).createAndProcessKarafInstance( anyString() );
boolean startup = karafBoot.startup( session );
// can't see if it started since we aren't actually starting up karaf, return value will be false
assertFalse( startup );
assertEquals( tmpDir, new File( System.getProperty( "karaf.home" ) ).getParentFile().getParentFile() );
} finally {
if ( origKarafHome == null ) {
System.getProperties().remove( "karaf.home" );
} else {
System.setProperty( "karaf.home", origKarafHome );
}
}
}
@Test
public void testStartupNotWritableConfigProps() throws Exception {
String origKarafHome = System.getProperty( "karaf.home" );
try {
System.getProperties().remove( "karaf.home" );
configProps.setWritable( false );
try ( FileOutputStream fileOutputStream = new FileOutputStream(
new File( tmpDir, "system/karaf/etc/custom.properties" ) ) ) {
fileOutputStream
.write( "org.osgi.framework.system.packages.extra=prop".getBytes( Charset.forName( "UTF-8" ) ) );
}
KarafBoot karafBoot = spy( boot );
doReturn( karafInstance ).when( karafBoot ).createAndProcessKarafInstance( anyString() );
boolean startup = karafBoot.startup( session );
// can't see if it started since we aren't actually starting up karaf, return value will be false
assertFalse( startup );
File karafHome = new File( System.getProperty( "karaf.home" ) );
assertNotEquals( tmpDir, karafHome.getParentFile().getParentFile() );
assertTrue( new File( karafHome, "system" ).exists() );
assertFalse( new File( karafHome, "caches" ).exists() );
} finally {
if ( origKarafHome == null ) {
System.getProperties().remove( "karaf.home" );
} else {
System.setProperty( "karaf.home", origKarafHome );
}
configProps.setWritable( true );
}
}
@Test
public void testStartupSetKarafDestFolder() throws Exception {
String origKarafHome = System.getProperty( "karaf.home" );
File tempDirectory = Files.createTempDirectory( "test" ).toFile();
tempDirectory.delete();
try {
System.getProperties().remove( "karaf.home" );
System.setProperty( KarafBoot.PENTAHO_KARAF_ROOT_COPY_DEST_FOLDER, tempDirectory.getAbsolutePath() );
try ( FileOutputStream fileOutputStream = new FileOutputStream(
new File( tmpDir, "system/karaf/etc/custom.properties" ) ) ) {
fileOutputStream
.write( "org.osgi.framework.system.packages.extra=prop".getBytes( Charset.forName( "UTF-8" ) ) );
}
KarafBoot karafBoot = spy( boot );
doReturn( karafInstance ).when( karafBoot ).createAndProcessKarafInstance( anyString() );
boolean startup = karafBoot.startup( session );
// can't see if it started since we aren't actually starting up karaf, return value will be false
assertFalse( startup );
File karafHome = new File( System.getProperty( "karaf.home" ) );
try {
assertEquals( tempDirectory, karafHome );
} catch ( AssertionError ae ) {
// don't throw an assertion error just yet; OSX likes to add its own files/folders into
// a folder ( think .DS_Store file or .Trash folder ), and also has its saying on the
// paths we can use ( think /private/var or /private/tmp instead of /var or /tmp )
if ( isOSX() ) {
assertEquals( ( "/private" + tempDirectory.getAbsolutePath() ), karafHome.getAbsolutePath() );
} else {
throw ae;
}
}
assertTrue( new File( karafHome, "system" ).exists() );
assertFalse( new File( karafHome, "caches" ).exists() );
} finally {
if ( origKarafHome == null ) {
System.getProperties().remove( "karaf.home" );
} else {
System.setProperty( "karaf.home", origKarafHome );
}
System.getProperties().remove( KarafBoot.PENTAHO_KARAF_ROOT_COPY_DEST_FOLDER );
FileUtils.deleteDirectory( tempDirectory );
}
}
@Test
public void testStartupSetKarafDestFolderTransient() throws Exception {
String origKarafHome = System.getProperty( "karaf.home" );
File tempDirectory = Files.createTempDirectory( "test" ).toFile();
try {
System.getProperties().remove( "karaf.home" );
System.setProperty( KarafBoot.PENTAHO_KARAF_ROOT_COPY_DEST_FOLDER, tempDirectory.getAbsolutePath() );
System.setProperty( KarafBoot.PENTAHO_KARAF_ROOT_TRANSIENT, "true" );
try ( FileOutputStream fileOutputStream = new FileOutputStream(
new File( tmpDir, "system/karaf/etc/custom.properties" ) ) ) {
fileOutputStream
.write( "org.osgi.framework.system.packages.extra=prop".getBytes( Charset.forName( "UTF-8" ) ) );
}
KarafBoot karafBoot = spy( boot );
doReturn( karafInstance ).when( karafBoot ).createAndProcessKarafInstance( anyString() );
boolean startup = karafBoot.startup( session );
// can't see if it started since we aren't actually starting up karaf, return value will be false
assertFalse( startup );
File karafHome = new File( System.getProperty( "karaf.home" ) );
assertEquals( tempDirectory.getParent(), karafHome.getParent() );
assertTrue( karafHome.getName().startsWith( tempDirectory.getName() ) );
assertTrue( new File( karafHome, "system" ).exists() );
assertFalse( new File( karafHome, "caches" ).exists() );
} finally {
if ( origKarafHome == null ) {
System.getProperties().remove( "karaf.home" );
} else {
System.setProperty( "karaf.home", origKarafHome );
}
System.getProperties().remove( KarafBoot.PENTAHO_KARAF_ROOT_COPY_DEST_FOLDER );
System.getProperties().remove( KarafBoot.PENTAHO_KARAF_ROOT_TRANSIENT );
FileUtils.deleteDirectory( tempDirectory );
}
}
@Test
public void testStartup_withOsxAppRootDir() throws Exception {
KarafBoot karafBoot = spy( boot );
when( appContext.getSolutionRootPath() ).thenReturn( null );
doReturn( karafInstance ).when( karafBoot ).createAndProcessKarafInstance( anyString() );
System.setProperty( "osx.app.root.dir", tmpDir.getPath() );
doReturn( KettleClientEnvironment.ClientType.KITCHEN ).when( karafBoot ).getClientType();
boolean startup = karafBoot.startup( session );
// can't see if it started since we aren't actually starting up karaf, return value will be false
assertFalse( startup );
}
@Test
public void testBuildExtraKettleEtc() throws Exception {
assertEquals( "/etc-carte", boot.translateToExtraKettleEtc( KettleClientEnvironment.ClientType.CARTE ) );
assertEquals( "/etc-default", boot.translateToExtraKettleEtc( KettleClientEnvironment.ClientType.DI_SERVER ) );
assertEquals( "/etc-kitchen", boot.translateToExtraKettleEtc( KettleClientEnvironment.ClientType.KITCHEN ) );
assertEquals( "/etc-pan", boot.translateToExtraKettleEtc( KettleClientEnvironment.ClientType.PAN ) );
assertEquals( "/etc-spoon", boot.translateToExtraKettleEtc( KettleClientEnvironment.ClientType.SPOON ) );
assertEquals( "/etc-default", boot.translateToExtraKettleEtc( null ) );
}
@Test
public void testConfigureSystemProperties_karafHome() throws Exception {
testConfigureSystemProperties( "karaf.home", "karaf.home" );
}
@Test
public void testConfigureSystemProperties_karafBase() throws Exception {
testConfigureSystemProperties( "karaf.base", "karaf.base" );
}
@Test
public void testConfigureSystemProperties_karafHistory() throws Exception {
testConfigureSystemProperties( "karaf.history", "karaf.history" );
}
@Test
public void testConfigureSystemProperties_karafInstances() throws Exception {
testConfigureSystemProperties( "karaf.instances", "karaf.instances" );
}
@Test
public void testConfigureSystemProperties_startLocalConsole() throws Exception {
testConfigureSystemProperties( "karaf.startLocalConsole", "karaf.startLocalConsole" );
}
@Test
public void testConfigureSystemProperties_startRemoteShell() throws Exception {
testConfigureSystemProperties( "karaf.startRemoteShell", "karaf.startRemoteShell" );
}
@Test
public void testConfigureSystemProperties_karafLock() throws Exception {
testConfigureSystemProperties( "karaf.lock", "karaf.lock" );
}
private void testConfigureSystemProperties( String propertyName, String expected ) throws Exception {
//set property
System.setProperty( propertyName, expected );
KarafBoot karafBoot = new KarafBoot();
karafBoot.configureSystemProperties( "solutionRootPath", "root" );
//check that property does not everrided
assertEquals( expected, System.getProperty( propertyName ) );
}
@Test
public void testClearDataCacheSetting() throws Exception {
// clear Karaf's property to avoid tests' interdependency
System.clearProperty( "karaf.data" );
PentahoSystem.init( new StandaloneApplicationContext( TestResourceLocation.TEST_RESOURCES + "/karafBootTest", "." ) );
//set property
KarafBoot karafBoot = new KarafBoot();
File root = Files.createTempDirectory( "root" ).toFile();
File caches = new File( root, "caches" );
caches.mkdir();
for ( int i = 0; i < 5; i++ ) {
File clientTypeFolder = new File( caches, "client" + i );
clientTypeFolder.mkdir();
for ( int y = 0; y < 3; y++ ) {
new File( clientTypeFolder, "data-" + y ).mkdir();
}
}
FileUtils.copyDirectory( new File( TestResourceLocation.TEST_RESOURCES + "/karafBootTest/system/karaf/etc" ), new File( root, "etc" ) );
Properties config = new Properties();
File configFile = new File( root + "/etc/custom.properties" );
config.load( new FileInputStream( configFile ) );
config.setProperty( "org.pentaho.clean.karaf.cache", "true" );
config.store( new FileOutputStream( configFile ), "setting stage" );
karafBoot.cleanCachesIfFlagSet( root.getPath() );
// Check that all data directories are gone
for ( int i = 0; i < 5; i++ ) {
File clientTypeFolder = new File( caches, "client" + i );
File[] files = clientTypeFolder.listFiles();
assertEquals( 0, files.length );
}
config.load( new FileInputStream( configFile ) );
assertEquals( "false", config.getProperty( "org.pentaho.clean.karaf.cache" ) );
}
private boolean isOSX() {
final String MAC_OS_BASE_NAME = "mac";
try {
String osName = System.getProperty( "os.name", "unknown" /* fallback value */ ).toLowerCase( Locale.ENGLISH );
return osName.startsWith( MAC_OS_BASE_NAME ); // osName is NPE-safe
} catch ( Throwable t ) {
// do not propagate any errors upwards; this is a quick-&-simple helper method,
// solely due to the fact that OSX likes to add its own files/folders into a folder
// ( think .DS_Store or .Trash ), and also has its saying on the paths we can use
// ( think /private/var or /private/tmp instead of /var or /tmp )
}
return false;
}
}