/**
* Copyright (c) 2002-2014 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.index.impl.lucene;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.junit.Ignore;
import org.junit.Test;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.index.IndexManager;
import org.neo4j.helpers.collection.MapUtil;
import org.neo4j.index.Neo4jTestCase;
import org.neo4j.kernel.DefaultFileSystemAbstraction;
import org.neo4j.kernel.impl.index.IndexStore;
import static org.junit.Assert.*;
public class TestMigration
{
@Test
public void canReadAndUpgradeOldIndexStoreFormat() throws Exception
{
String path = "target/var/old-index-store";
Neo4jTestCase.deleteFileOrDirectory( new File( path ) );
GraphDatabaseService db = new GraphDatabaseFactory().newEmbeddedDatabase( path );
db.shutdown();
InputStream stream = getClass().getClassLoader().getResourceAsStream( "old-index.db" );
writeFile( stream, new File( path, "index.db" ) );
db = new GraphDatabaseFactory().newEmbeddedDatabase( path );
assertTrue( db.index().existsForNodes( "indexOne" ) );
Index<Node> indexOne = db.index().forNodes( "indexOne" );
verifyConfiguration( db, indexOne, LuceneIndexImplementation.EXACT_CONFIG );
assertTrue( db.index().existsForNodes( "indexTwo" ) );
Index<Node> indexTwo = db.index().forNodes( "indexTwo" );
verifyConfiguration( db, indexTwo, LuceneIndexImplementation.FULLTEXT_CONFIG );
assertTrue( db.index().existsForRelationships( "indexThree" ) );
Index<Relationship> indexThree = db.index().forRelationships( "indexThree" );
verifyConfiguration( db, indexThree, LuceneIndexImplementation.EXACT_CONFIG );
db.shutdown();
}
@Test
@Ignore( "These upgrade tests only work for one version difference" )
public void canUpgradeFromPreviousVersion() throws Exception
{
GraphDatabaseService db = unpackDbFrom( "db-with-v3.0.1.zip" );
Index<Node> index = db.index().forNodes( "v3.0.1" );
Node node = index.get( "key", "value" ).getSingle();
assertNotNull( node );
db.shutdown();
}
private GraphDatabaseService unpackDbFrom( String file ) throws IOException
{
File path = new File( "target/var/zipup" );
ZipInputStream zip = new ZipInputStream( getClass().getClassLoader().getResourceAsStream( file ) );
ZipEntry entry = null;
byte[] buffer = new byte[2048];
while ( (entry = zip.getNextEntry()) != null )
{
if ( entry.isDirectory() )
{
new File( path, entry.getName() ).mkdirs();
continue;
}
FileOutputStream fos = new FileOutputStream( new File( path, entry.getName() ) );
BufferedOutputStream bos = new BufferedOutputStream( fos, buffer.length );
int size;
while ( (size = zip.read( buffer, 0, buffer.length )) != -1 )
{
bos.write( buffer, 0, size );
}
bos.flush();
bos.close();
}
return new GraphDatabaseFactory().newEmbeddedDatabase( path.getAbsolutePath() );
}
private void verifyConfiguration( GraphDatabaseService db, Index<? extends PropertyContainer> index, Map<String, String> config )
{
assertEquals( config, db.index().getConfiguration( index ) );
}
private void writeFile( InputStream stream, File file ) throws Exception
{
file.delete();
OutputStream out = new FileOutputStream( file );
byte[] bytes = new byte[1024];
int bytesRead = 0;
while ( (bytesRead = stream.read( bytes )) >= 0 )
{
out.write( bytes, 0, bytesRead );
}
out.close();
}
@Test
public void providerGetsFilledInAutomatically()
{
Map<String, String> correctConfig = MapUtil.stringMap( "type", "exact", IndexManager.PROVIDER, "lucene" );
File storeDir = new File( "target/var/index" );
Neo4jTestCase.deleteFileOrDirectory( storeDir );
GraphDatabaseService graphDb = new GraphDatabaseFactory().newEmbeddedDatabase( storeDir.getPath() );
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forNodes( "default" ) ) );
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forNodes( "wo-provider", MapUtil.stringMap( "type", "exact" ) ) ) );
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forNodes( "w-provider", MapUtil.stringMap( "type", "exact", IndexManager.PROVIDER, "lucene" ) ) ) );
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forRelationships( "default" ) ) );
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forRelationships( "wo-provider", MapUtil.stringMap( "type", "exact" ) ) ) );
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forRelationships( "w-provider", MapUtil.stringMap( "type", "exact", IndexManager.PROVIDER, "lucene" ) ) ) );
graphDb.shutdown();
removeProvidersFromIndexDbFile( storeDir );
graphDb = new GraphDatabaseFactory().newEmbeddedDatabase( storeDir.getPath() );
// Getting the index w/o exception means that the provider has been reinstated
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forNodes( "default" ) ) );
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forNodes( "wo-provider", MapUtil.stringMap( "type", "exact" ) ) ) );
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forNodes( "w-provider", MapUtil.stringMap( "type", "exact", IndexManager.PROVIDER, "lucene" ) ) ) );
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forRelationships( "default" ) ) );
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forRelationships( "wo-provider", MapUtil.stringMap( "type", "exact" ) ) ) );
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forRelationships( "w-provider", MapUtil.stringMap( "type", "exact", IndexManager.PROVIDER, "lucene" ) ) ) );
graphDb.shutdown();
removeProvidersFromIndexDbFile( storeDir );
graphDb = new GraphDatabaseFactory().newEmbeddedDatabase( storeDir.getPath() );
// Getting the index w/o exception means that the provider has been reinstated
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forNodes( "default" ) ) );
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forNodes( "wo-provider" ) ) );
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forNodes( "w-provider" ) ) );
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forRelationships( "default" ) ) );
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forRelationships( "wo-provider" ) ) );
assertEquals( correctConfig, graphDb.index().getConfiguration( graphDb.index().forRelationships( "w-provider" ) ) );
graphDb.shutdown();
}
private void removeProvidersFromIndexDbFile( File storeDir )
{
IndexStore indexStore = new IndexStore( storeDir.getPath(), new DefaultFileSystemAbstraction() );
for ( Class<? extends PropertyContainer> cls : new Class[] {Node.class, Relationship.class} )
{
for ( String name : indexStore.getNames( cls ) )
{
Map<String, String> config = indexStore.get( cls, name );
config = new HashMap<String, String>( config );
config.remove( IndexManager.PROVIDER );
indexStore.set( Node.class, name, config );
}
}
}
}