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.api.core.Transaction;
import org.neo4j.impl.event.EventData;
import org.neo4j.impl.event.EventManager;
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.SecurityMgr4;

public class TestSecurity4 extends TestCase
{
	public TestSecurity4( String testName )
	{
		super( testName );
	}
	
	public static Test suite()
	{
		TestSuite suite = new TestSuite( TestSecurity4.class );
		return suite;
	}
	
	private SecurityMgr4 securityManager = new SecurityMgr4();
	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 testSimpleSecurityMgr4()
	{
		Node root = neo.createNode();
		Node file = neo.createNode();
		Node otherUser = neo.createNode();
		Node group1 = neo.createNode();
		Node group2 = neo.createNode();
		Node group3 = neo.createNode();
		Relationship fileRel = root.createRelationshipTo( file, 
			MyRelationshipTypes.FILE );
		// rU -> g2 -> g1
		// oU -> g3 -> g1
		Relationship member1,member2,member3,member4;
		member1 = registeredUser.createRelationshipTo( group2, 
			MyRelationshipTypes.MEMBER_OF );
		member2 = group2.createRelationshipTo( group1, 
			MyRelationshipTypes.MEMBER_OF );
		member3 = otherUser.createRelationshipTo( group3, 
			MyRelationshipTypes.MEMBER_OF );
		member4 = group3.createRelationshipTo( group1, 
			MyRelationshipTypes.MEMBER_OF );
		tx.success();
		tx.finish();
		tx = Transaction.begin();
		Relationship access1 = null, access2 = null;
		EventManager evtMgr = EventManager.getManager();
		EventData eventData = new EventData( file );
		try
		{
			// no ACCESS relationship should grant access
			assertTrue( evtMgr.generateProActiveEvent( 
				SecurityEvent.ACCESS, eventData ) );
			// add other user (group3), false should be returned now
			access1 = root.createRelationshipTo( group3, 
				MyRelationshipTypes.ACCESS );
			assertTrue( !evtMgr.generateProActiveEvent( 
				SecurityEvent.ACCESS, eventData ) );
			// add registered user (via group1), true should be returned
			access2 = root.createRelationshipTo( group1, 
				MyRelationshipTypes.ACCESS );
			assertTrue( evtMgr.generateProActiveEvent( 
				SecurityEvent.ACCESS, eventData ) );
		}
		finally
		{
			if ( access1 != null )
			{
				access1.delete();
			}
			if ( access2 != null )
			{
				access2.delete();
			}
			fileRel.delete();
			member1.delete();
			member2.delete();
			member3.delete();
			member4.delete();
			otherUser.delete();
			file.delete();
			root.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 );
		Node group1 = neo.createNode();
		Node group2 = neo.createNode();
		Node group3 = neo.createNode();
		// rU -> g2 -> g1
		// oU -> g3 -> g1
		Relationship member1,member2,member3,member4;
		member1 = registeredUser.createRelationshipTo( group2, 
			MyRelationshipTypes.MEMBER_OF );
		member2 = group2.createRelationshipTo( group1, 
			MyRelationshipTypes.MEMBER_OF );
		member3 = otherUser.createRelationshipTo( group3, 
			MyRelationshipTypes.MEMBER_OF );
		member4 = group3.createRelationshipTo( group1, 
			MyRelationshipTypes.MEMBER_OF );
		Relationship rel1;
		rel1 = root.getUnderlyingNode().createRelationshipTo( group1, 
			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 ) ||
					file.equals( file2 ) || file.equals( file4 ) );
				count++;
			}
			assertEquals( 4, count );
		}
		finally
		{
			member1.delete();
			member2.delete();
			member3.delete();
			member4.delete();
			rel1.delete();
			root.delete();
			otherUser.delete();
			tx.success();
		}
	}
}
