package unit.security;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

import org.neo4j.api.core.EmbeddedNeo;
import org.neo4j.api.core.Node;
import org.neo4j.api.core.Relationship;
import org.neo4j.impl.event.EventData;
import org.neo4j.impl.event.EventManager;
import org.neo4j.api.core.Transaction;
import org.neo4j.tutor.security.AuthorizationService;
import org.neo4j.tutor.security.File;
import org.neo4j.tutor.security.FileFactory;
import org.neo4j.tutor.security.MyRelationshipTypes;
import org.neo4j.tutor.security.SecurityEvent;
import org.neo4j.tutor.security.SecurityMgr2;

public class TestSecurity2 extends TestCase
{
	public TestSecurity2( String testName )
	{
		super( testName );
	}
	
	public static Test suite()
	{
		TestSuite suite = new TestSuite( TestSecurity2.class );
		return suite;
	}
	
	private SecurityMgr2 securityManager = new SecurityMgr2();
	private Node registeredUser;
	private EmbeddedNeo neo;
	private Transaction tx;
	
	public void setUp()
	{
		neo = new EmbeddedNeo( MyRelationshipTypes.class, "var/security-test", 
			true );
		securityManager.registerEventListener();
		FileFactory.getFactory().injectNeo( neo );
		tx = Transaction.begin();
		registeredUser = neo.createNode();
		AuthorizationService.authenticate( registeredUser );
	}
	
	public void tearDown()
	{
		AuthorizationService.unregisterUser();
		registeredUser.delete();
		tx.finish();
		securityManager.unregisterEventListner();
		neo.shutdown();
	}
	
	public void testSimpleSecurityMgr2()
	{
		Node fileNode = neo.createNode();
		Node otherUser = neo.createNode();
		tx.success();
		tx.finish();
		tx = Transaction.begin();
		Relationship access1 = null,access2 = null;
		EventManager evtMgr = EventManager.getManager();
		EventData eventData = new EventData( fileNode );
		try
		{
			// no ACCESS relationship should grant access
			assertTrue( evtMgr.generateProActiveEvent( 
				SecurityEvent.ACCESS, eventData ) );
			// add other user, false should be returned now
			access1 = fileNode.createRelationshipTo( otherUser, 
				MyRelationshipTypes.ACCESS );
			assertTrue( !evtMgr.generateProActiveEvent( 
				SecurityEvent.ACCESS, eventData ) );
			// add registered user, true should be returned
			access2 = fileNode.createRelationshipTo( registeredUser, 
				MyRelationshipTypes.ACCESS );
			assertTrue( evtMgr.generateProActiveEvent( 
				SecurityEvent.ACCESS, eventData ) );
		}
		finally
		{
			if ( access1 != null )
			{
				access1.delete();
			}
			if ( access2 != null )
			{
				access2.delete();
			}
			otherUser.delete();
			fileNode.delete();
			tx.success();
		}
	}
	
	public void testGetChildren()
	{
		FileFactory factory = FileFactory.getFactory();
		Node otherUser = neo.createNode();
		File root = factory.createNewFile( "root" );
		File file1 = factory.createNewFile( "fileAccessOk1" );
		File file2 = factory.createNewFile( "fileNoAccess1" );
		File file3 = factory.createNewFile( "fileAccessOk2" );
		File file4 = factory.createNewFile( "fileNoAccess2" );
		root.addChild( file1 );
		root.addChild( file2 );
		root.addChild( file3 );
		root.addChild( file4 );
		Relationship rel1, rel2, rel3, rel4;
		rel1 = file1.getUnderlyingNode().createRelationshipTo( registeredUser, 
			MyRelationshipTypes.ACCESS );
		rel2 = file2.getUnderlyingNode().createRelationshipTo( otherUser, 
			MyRelationshipTypes.ACCESS );
		rel3 = file3.getUnderlyingNode().createRelationshipTo( registeredUser, 
			MyRelationshipTypes.ACCESS );
		rel4 = file4.getUnderlyingNode().createRelationshipTo( otherUser, 
			MyRelationshipTypes.ACCESS );
		tx.success();
		tx.finish();
		tx = Transaction.begin();
		try
		{
			int count = 0;
			for ( File file : root.getChildren() )
			{
				assertTrue( file.equals( file1 ) || file.equals( file3 ) );
				count++;
			}
			assertEquals( 2, count );
		}
		finally
		{
			rel1.delete();
			rel2.delete();
			rel3.delete();
			rel4.delete();
			root.delete();
			otherUser.delete();
			tx.success();
		}
	}
}
