/* * JBoss, Home of Professional Open Source * Copyright 2005, JBoss Inc., and individual contributors as indicated * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.test.security.acl; import java.util.ArrayList; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; import junit.framework.TestCase; import org.jboss.security.acl.ACL; import org.jboss.security.acl.ACLEntry; import org.jboss.security.acl.ACLEntryImpl; import org.jboss.security.acl.ACLImpl; import org.jboss.security.acl.BasicACLPermission; import org.jboss.security.acl.CompositeACLPermission; import org.jboss.security.acl.Util; import org.jboss.security.identity.plugins.IdentityFactory; /** * <p> * This {@code TestCase} tests the functionality of the persistence layer added to the {@code ACL} implementation * classes. It uses an in-memory hsql test database, so there is no need to perform any special database cleanup in case * one of the tests fail. Every time the tests are run a clean new database is used. * </p> * * @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a> */ public class PersistenceTestCase extends TestCase { private EntityManagerFactory entityManagerFactory; private EntityManager entityManager; private List<ACLEntryImpl> persistedEntries; private List<ACLImpl> persistedACLs; /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { this.entityManagerFactory = Persistence.createEntityManagerFactory("ACL"); this.entityManager = entityManagerFactory.createEntityManager(); this.persistedACLs = new ArrayList<ACLImpl>(); this.persistedEntries = new ArrayList<ACLEntryImpl>(); // create the test entries. this.persistedEntries .add(new ACLEntryImpl(BasicACLPermission.READ, IdentityFactory.createIdentity("Identity-1"))); this.persistedEntries.add(new ACLEntryImpl(new CompositeACLPermission(BasicACLPermission.CREATE, BasicACLPermission.READ), IdentityFactory.createIdentity("Identity-2"))); this.persistedEntries.add(new ACLEntryImpl(new CompositeACLPermission(BasicACLPermission.values()), IdentityFactory.createIdentity("Identity-3"))); // create the test acls. this.persistedACLs.add(new ACLImpl(new TestResource(100, "Resource-1"))); this.persistedACLs.add(new ACLImpl(new TestResource(200, "Resource-2"), new ArrayList<ACLEntry>( this.persistedEntries))); // persist everything. for (ACL acl : this.persistedACLs) this.persistEntity(acl); } /* * (non-Javadoc) * * @see junit.framework.TestCase#tearDown() */ @Override protected void tearDown() throws Exception { // remove the persisted entities - removing the acl also removes the entries. for (ACLImpl acl : this.persistedACLs) { // re-attach the acl before removing. ACLImpl attachedACL = this.entityManager.find(ACLImpl.class, acl.getACLId()); this.removeEntity(attachedACL); } // assert the acls have been removed. for (ACLImpl acl : this.persistedACLs) assertNull(this.entityManager.find(ACLImpl.class, acl.getACLId())); // assert the entries have been also removed. for (ACLEntryImpl entry : this.persistedEntries) assertNull(this.entityManager.find(ACLEntryImpl.class, entry.getACLEntryId())); if (this.entityManager != null) entityManager.close(); this.entityManagerFactory.close(); } /** * <p> * Tests persisting the {@code ACLEntry} objects to a database. * </p> * * @throws Exception if an error occurs when running the test. */ public void testPersistACLEntry() throws Exception { // assert the entries have been created by checking if the auto-generated id has been set on each entry. assertTrue("Entry1 id value has not been generated", this.persistedEntries.get(0).getACLEntryId() > 0); assertTrue("Entry2 id value has not been generated", this.persistedEntries.get(1).getACLEntryId() > 0); assertTrue("Entry3 id value has not been generated", this.persistedEntries.get(2).getACLEntryId() > 0); } /** * <p> * Tests searching for the persisted {@code ACLEntry} objects. * </p> * * @throws Exception if an error occurs when running the test. */ public void testSearchACLEntry() throws Exception { // clear the entity manager so that it goes to the database when searching for entries. this.entityManager.clear(); // load the entries from the database using their primary key and validate them. for (ACLEntryImpl entry : this.persistedEntries) { ACLEntryImpl loadedEntry = this.entityManager.find(ACLEntryImpl.class, entry.getACLEntryId()); assertNotNull("Entry could not be retrieved by primary key", loadedEntry); assertEquals(entry, loadedEntry); } // execute some queries and validate the results. ACLEntryImpl entry = this.persistedEntries.get(1); ACLEntryImpl queryResult = (ACLEntryImpl) this.entityManager.createQuery( "SELECT e FROM ACLEntryImpl e WHERE e.identityOrRole LIKE '" + entry.getIdentityOrRole() + "'").getSingleResult(); assertNotNull("Entry2 could not be retrieved by it's identity", queryResult); assertEquals(entry, queryResult); entry = this.persistedEntries.get(0); queryResult = (ACLEntryImpl) this.entityManager.createQuery( "SELECT e FROM ACLEntryImpl e WHERE e.bitMask = " + BasicACLPermission.READ.getMaskValue()) .getSingleResult(); assertNotNull("Entry1 could not be retrieved by it's bitmask value", queryResult); assertEquals(entry, queryResult); } /** * <p> * Tests persisting the {@code ACL} objects to a database. * </p> * * @throws Exception if an error occurs when running the test. */ public void testPersistACL() throws Exception { // assert the ACLs and their associated entries have been persisted for (ACLImpl acl : this.persistedACLs) { assertTrue("ACL id value has not been generated", acl.getACLId() > 0); for (ACLEntry entry : acl.getEntries()) assertTrue("ACL entry has not been persisted", ((ACLEntryImpl) entry).getACLEntryId() > 0); } } /** * <p> * Tests searching for the persisted {@code ACL} objects. * </p> * * @throws Exception if an error occurs when running the test. */ public void testSearchACL() throws Exception { // clear the entity manager's cache. this.entityManager.clear(); // load the ACLs from the database using their primary key and validate them. ACLImpl loadedACL1 = this.entityManager.find(ACLImpl.class, this.persistedACLs.get(0).getACLId()); assertNotNull("ACL1 could not be retrieved", loadedACL1); assertEquals("Loaded ACL contains unexpected number of entries", 0, loadedACL1.getEntries().size()); assertNull(loadedACL1.getResource()); ACLImpl loadedACL2 = this.entityManager.find(ACLImpl.class, this.persistedACLs.get(1).getACLId()); assertNotNull("ACL2 could not be retrieved", loadedACL2); assertEquals("Loaded ACL contains unexpected number of entries", 3, loadedACL2.getEntries().size()); assertTrue(loadedACL2.getEntries().contains(this.persistedEntries.get(0))); assertTrue(loadedACL2.getEntries().contains(this.persistedEntries.get(1))); assertTrue(loadedACL2.getEntries().contains(this.persistedEntries.get(2))); assertNull(loadedACL2.getResource()); // find the ACLs using the resource and validate the result. ACLImpl acl = this.persistedACLs.get(0); ACLImpl queryResult = (ACLImpl) this.entityManager.createQuery( "SELECT a FROM ACLImpl a WHERE a.resourceAsString LIKE '" + Util.getResourceAsString(acl.getResource()) + "'").getSingleResult(); assertNotNull("ACL1 could not be retrieved by it's resource", queryResult); assertEquals("Queried ACL id does not match the expected id", acl.getACLId(), queryResult.getACLId()); assertEquals("Queried ACL contains unexpected number of entries", 0, queryResult.getEntries().size()); acl = this.persistedACLs.get(1); queryResult = (ACLImpl) this.entityManager.createQuery( "SELECT a FROM ACLImpl a WHERE a.resourceAsString LIKE '" + Util.getResourceAsString(acl.getResource()) + "'").getSingleResult(); assertNotNull("ACL2 could not be retrieved by it's resource", queryResult); assertEquals("Queried ACL id does not match the expected id", acl.getACLId(), queryResult.getACLId()); assertEquals("Queried ACL contains unexpected number of entries", 3, queryResult.getEntries().size()); assertTrue(queryResult.getEntries().contains(this.persistedEntries.get(0))); assertTrue(queryResult.getEntries().contains(this.persistedEntries.get(1))); assertTrue(queryResult.getEntries().contains(this.persistedEntries.get(2))); } /** * <p> * Tests updating the persisted {@code ACL} objects. * </p> * * @throws Exception if an error occurs when running the test. */ public void testUpdateACL() throws Exception { // add some entries to the acls and remove one of the existing entries from ACL2. ACLEntryImpl entry4 = new ACLEntryImpl(BasicACLPermission.CREATE, IdentityFactory.createIdentity("Identity-4")); ACLEntryImpl entry5 = new ACLEntryImpl(new CompositeACLPermission(BasicACLPermission.CREATE, BasicACLPermission.DELETE), IdentityFactory.createIdentity("Identity-5")); ACLEntryImpl entry6 = new ACLEntryImpl(new CompositeACLPermission(BasicACLPermission.values()), IdentityFactory .createIdentity("Identity-6")); ACLImpl acl1 = null; ACLImpl acl2 = null; EntityTransaction transaction = this.entityManager.getTransaction(); transaction.begin(); try { acl1 = this.entityManager.merge(this.persistedACLs.get(0)); acl1.addEntry(entry4); acl1.addEntry(entry5); acl2 = this.entityManager.merge(this.persistedACLs.get(1)); acl2.addEntry(entry6); acl2.removeEntry(this.persistedEntries.get(0)); transaction.commit(); } catch (RuntimeException re) { re.printStackTrace(); transaction.rollback(); } // add the new entries to the persisted entries collection. this.persistedEntries.add(entry4); this.persistedEntries.add(entry5); this.persistedEntries.add(entry6); // clear the entity manager's cache. this.entityManager.clear(); // load the ACLs again and validate the changes. ACLImpl loadedACL1 = this.entityManager.find(ACLImpl.class, acl1.getACLId()); assertNotNull("ACL1 could not be retrieved", loadedACL1); assertEquals("Loaded ACL contains unexpected number of entries", 2, loadedACL1.getEntries().size()); assertTrue(loadedACL1.getEntries().contains(entry4)); assertTrue(loadedACL1.getEntries().contains(entry5)); ACLImpl loadedACL2 = this.entityManager.find(ACLImpl.class, acl2.getACLId()); assertNotNull("ACL2 could not be retrieved", loadedACL2); assertEquals("Loaded AC2 contains unexpected number of entries", 3, loadedACL2.getEntries().size()); assertFalse(loadedACL2.getEntries().contains(this.persistedEntries.get(0))); assertTrue(loadedACL2.getEntries().contains(this.persistedEntries.get(1))); assertTrue(loadedACL2.getEntries().contains(this.persistedEntries.get(2))); assertTrue(loadedACL2.getEntries().contains(entry6)); } /** * <p> * Persists the specified entity to the database. * </p> * * @param entity an {@code Object} representing the entity to be persisted. */ private void persistEntity(Object entity) { EntityTransaction transaction = this.entityManager.getTransaction(); transaction.begin(); try { this.entityManager.persist(entity); transaction.commit(); } catch (RuntimeException re) { re.printStackTrace(); transaction.rollback(); } } /** * <p> * Removes the specified entity from the database. * </p> * * @param entity an {@code Object} representing the entity to be removed. */ private void removeEntity(Object entity) { EntityTransaction transaction = this.entityManager.getTransaction(); transaction.begin(); try { this.entityManager.remove(entity); transaction.commit(); } catch (RuntimeException re) { re.printStackTrace(); transaction.rollback(); } } }