/**
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community 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://opensource.org/licenses/ecl2.txt
*
* 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.opencastproject.authorization.xacml.manager.impl.persistence;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.opencastproject.util.data.Option.none;
import static org.opencastproject.util.data.Option.option;
import static org.opencastproject.util.data.Option.some;
import static org.opencastproject.util.persistence.PersistenceEnvs.persistenceEnvironment;
import static org.opencastproject.util.persistence.PersistenceUtil.newTestEntityManagerFactory;
import static org.opencastproject.workflow.api.ConfiguredWorkflowRef.workflow;
import org.opencastproject.authorization.xacml.manager.api.EpisodeACLTransition;
import org.opencastproject.authorization.xacml.manager.api.ManagedAcl;
import org.opencastproject.authorization.xacml.manager.api.SeriesACLTransition;
import org.opencastproject.authorization.xacml.manager.api.TransitionQuery;
import org.opencastproject.authorization.xacml.manager.api.TransitionResult;
import org.opencastproject.authorization.xacml.manager.impl.AclTransitionDbDuplicatedException;
import org.opencastproject.authorization.xacml.manager.impl.AclTransitionDbException;
import org.opencastproject.security.api.AccessControlList;
import org.opencastproject.security.api.AccessControlParser;
import org.opencastproject.security.api.AclScope;
import org.opencastproject.security.api.DefaultOrganization;
import org.opencastproject.security.api.JaxbOrganization;
import org.opencastproject.security.api.Organization;
import org.opencastproject.security.api.SecurityService;
import org.opencastproject.util.NotFoundException;
import org.opencastproject.util.data.Option;
import org.opencastproject.workflow.api.ConfiguredWorkflowRef;
import org.apache.commons.io.IOUtils;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import javax.persistence.EntityManagerFactory;
/** Tests persistence: storing, merging, retrieving and removing. */
public class OsgiJpaAclTransitionDbTest {
private static final String ACL_FILE = "/acl.xml";
private static final Organization ORG = new DefaultOrganization();
private static final Organization ORG2 = new JaxbOrganization("another-org");
private OsgiJpaAclTransitionDb db;
private JpaAclDb aclDb;
private AccessControlList acl;
private SecurityService securityService;
/** @throws java.lang.Exception */
@Before
public void setUp() throws Exception {
securityService = EasyMock.createNiceMock(SecurityService.class);
EasyMock.expect(securityService.getOrganization()).andReturn(new DefaultOrganization()).anyTimes();
EasyMock.replay(securityService);
db = new OsgiJpaAclTransitionDb();
EntityManagerFactory emf = newTestEntityManagerFactory(OsgiJpaAclTransitionDb.PERSISTENCE_UNIT);
db.setEntityManagerFactory(emf);
db.activate(null);
aclDb = new JpaAclDb(persistenceEnvironment(emf));
InputStream in = null;
try {
in = getClass().getResourceAsStream(ACL_FILE);
acl = AccessControlParser.parseAcl(in);
} finally {
IOUtils.closeQuietly(in);
}
}
@Test
public void createEpisodeAclTransitionEntity() {
final Date now = new Date();
EpisodeAclTransitionEntity e = new EpisodeAclTransitionEntity().update("uuid", ORG.getId(), now, Option.<ManagedAclEntity>none(), Option.<ConfiguredWorkflowRef>none());
assertEquals("uuid", e.getEpisodeId());
assertEquals(now, e.getApplicationDate());
assertEquals(ORG.getId(), e.getOrganizationId());
}
@Test
public void testStoreAndGetEpisodeACL() throws Exception {
final Date now = new Date();
// a fallback to series transition should be saveable
db.storeEpisodeAclTransition(ORG, "uuid", now, none(0L), Option.<ConfiguredWorkflowRef>none());
// a transition referencing a non existing ACL should not be saveable
try {
db.storeEpisodeAclTransition(ORG, "uuid", new Date(), some(1L), Option.<ConfiguredWorkflowRef>none());
fail("No ACL with ID 1");
} catch (AclTransitionDbException ignore) {
}
// a transition referencing an existing ACL should be saveable
final ManagedAcl macl = createAcl();
final EpisodeACLTransition t3 = db.storeEpisodeAclTransition(ORG, "uuid-2", now, some(macl.getId()), Option.<ConfiguredWorkflowRef>none());
assertEquals("uuid-2", t3.getEpisodeId());
assertEquals(now, t3.getApplicationDate());
assertTrue(t3.getAccessControlList().isSome());
assertEquals(macl.getName(), t3.getAccessControlList().get().getName());
// a transition with the same properties should not be saveable
try {
db.storeEpisodeAclTransition(ORG, "uuid", now, some(macl.getId()), Option.<ConfiguredWorkflowRef>none());
fail("Duplicated episode ACL must not be stored");
} catch (AclTransitionDbDuplicatedException ignore) {
}
List<EpisodeACLTransition> ts = db.getEpisodeAclTransitions(ORG, "uuid");
assertEquals(1, ts.size());
assertEquals("uuid", ts.get(0).getEpisodeId());
assertTrue(ts.get(0).isDelete());
assertTrue(!ts.get(0).isDone());
}
@Test
public void testStoreAndGetSeriesACL() throws Exception {
final Date now = new Date();
// a transition referencing a non existing ACL should not be saveable
try {
db.storeSeriesAclTransition(ORG, "uuid", new Date(), 1L, true, Option.<ConfiguredWorkflowRef>none());
fail("No ACL with ID 1");
} catch (AclTransitionDbException ignore) {
}
// a transition referencing an existing ACL should be saveable
final ManagedAcl macl = createAcl();
final SeriesACLTransition t3 = db.storeSeriesAclTransition(ORG, "uuid", now, macl.getId(), false, Option.<ConfiguredWorkflowRef>none());
assertEquals("uuid", t3.getSeriesId());
assertEquals(now, t3.getApplicationDate());
assertEquals(macl.getName(), t3.getAccessControlList().getName());
// a transition with the same properties should not be saveable
try {
db.storeSeriesAclTransition(ORG, "uuid", now, macl.getId(), true, Option.<ConfiguredWorkflowRef>none());
fail("Duplicated episode ACL must not be stored");
} catch (AclTransitionDbDuplicatedException ignore) {
}
List<SeriesACLTransition> ts = db.getSeriesAclTransitions(ORG, "uuid");
assertEquals(1, ts.size());
assertEquals("uuid", ts.get(0).getSeriesId());
assertTrue(!ts.get(0).isOverride());
assertTrue(!ts.get(0).isDone());
}
@Test
public void testGetEpisodeTransitions() throws Exception {
final ManagedAcl macl = createAcl();
db.storeEpisodeAclTransition(ORG, "uuid", new Date(), some(macl.getId()), Option.<ConfiguredWorkflowRef> none());
db.storeEpisodeAclTransition(ORG, "uuid", new Date(), some(macl.getId()), Option.<ConfiguredWorkflowRef> none());
// there should now be two transitions for episode "uuid"
List<EpisodeACLTransition> episodes = db.getEpisodeAclTransitions(ORG, "uuid");
assertEquals(2, episodes.size());
// transitions shouldn't be accessible from another organization
assertEquals(0, db.getEpisodeAclTransitions(ORG2, "uuid").size());
}
@Test
public void testGetSeriesTransitions() throws Exception {
final ManagedAcl macl = createAcl();
db.storeSeriesAclTransition(ORG, "uuid", new Date(), macl.getId(), true, Option.<ConfiguredWorkflowRef> none());
db.storeSeriesAclTransition(ORG, "uuid", new Date(), macl.getId(), false, Option.<ConfiguredWorkflowRef> none());
// there should now be two transitions for series "uuid"
List<SeriesACLTransition> series = db.getSeriesAclTransitions(ORG, "uuid");
assertEquals(2, series.size());
// transitions shouldn't be accessible from another organization
assertEquals(0, db.getSeriesAclTransitions(ORG2, "uuid").size());
}
@Test
public void testUpdateEpisode() throws Exception {
final ManagedAcl macl = createAcl();
EpisodeACLTransition t1 = db.storeEpisodeAclTransition(ORG, "uuid", new Date(), some(macl.getId()), Option.<ConfiguredWorkflowRef>none());
EpisodeACLTransition u1 = db.updateEpisodeAclTransition(ORG, t1.getTransitionId(), t1.getApplicationDate(), none(0L), Option.some(workflow("full")));
assertEquals(t1.getTransitionId(), u1.getTransitionId());
assertEquals(t1.getEpisodeId(), u1.getEpisodeId());
assertEquals(t1.getOrganizationId(), u1.getOrganizationId());
assertTrue(u1.getAccessControlList().isNone());
assertNotSame(t1.isDelete(), u1.isDelete());
assertNotSame(t1.getWorkflow(), u1.getWorkflow());
try {
db.updateEpisodeAclTransition(ORG2, t1.getTransitionId(), t1.getApplicationDate(), some(macl.getId()), Option.some(workflow("full")));
fail("Updating from non-owner org should not be possible");
} catch (AclTransitionDbException ignore1) {
} catch (NotFoundException ignore2) {
}
}
@Test
public void testUpdateSeries() throws Exception {
final ManagedAcl macl = createAcl();
SeriesACLTransition t1 = db.storeSeriesAclTransition(ORG, "uuid", new Date(), macl.getId(), true, Option.<ConfiguredWorkflowRef>none());
SeriesACLTransition u1 = db.updateSeriesAclTransition(ORG, t1.getTransitionId(), t1.getApplicationDate(), macl.getId(), false, Option.some(workflow("full")));
assertEquals(t1.getTransitionId(), u1.getTransitionId());
assertEquals(t1.getSeriesId(), u1.getSeriesId());
assertEquals(t1.getOrganizationId(), u1.getOrganizationId());
assertEquals(t1.getAccessControlList().getId(), u1.getAccessControlList().getId());
assertNotSame(t1.getWorkflow(), u1.getWorkflow());
assertNotSame(t1.isOverride(), u1.isOverride());
try {
db.updateSeriesAclTransition(ORG2, t1.getTransitionId(), t1.getApplicationDate(), macl.getId(), false, Option.some(workflow("full")));
fail("Updating from non-owner org should not be possible");
} catch (AclTransitionDbException ignore1) {
} catch (NotFoundException ignore2) {
}
}
@Test
public void testDeleteEpisode() throws Exception {
final ManagedAcl macl = createAcl();
EpisodeACLTransition t1 = db.storeEpisodeAclTransition(ORG, "uuid", new Date(), some(macl.getId()), Option.<ConfiguredWorkflowRef>none());
// try deletion from different org
try {
db.deleteEpisodeAclTransition(ORG2, t1.getTransitionId());
fail("Deleting from non-owner org should not be possible");
} catch (NotFoundException ignore) {
}
db.deleteEpisodeAclTransition(ORG, t1.getTransitionId());
try {
db.deleteEpisodeAclTransition(ORG, t1.getTransitionId());
fail("Deleting a non existing transition should throw an exception");
} catch (NotFoundException ignore) {
}
}
@Test
public void testDeleteSeries() throws Exception {
final ManagedAcl macl = createAcl();
SeriesACLTransition t1 = db.storeSeriesAclTransition(ORG, "uuid", new Date(), macl.getId(), true, Option.<ConfiguredWorkflowRef>none());
// try deletion from different org
try {
db.deleteSeriesAclTransition(ORG2, t1.getTransitionId());
fail("Deleting from non-owner org should not be possible");
} catch (NotFoundException ignore) {
}
db.deleteSeriesAclTransition(ORG, t1.getTransitionId());
try {
db.deleteSeriesAclTransition(ORG, t1.getTransitionId());
fail("Deleting a non existing transition should throw an exception");
} catch (NotFoundException ignore) {
}
}
@Test
public void testGetByQuery() throws Exception {
final ManagedAcl macl = createAcl();
SeriesACLTransition st1 = db.storeSeriesAclTransition(ORG, "uuid-series", new Date(1347000000000L), macl.getId(), true, Option.<ConfiguredWorkflowRef>none());
SeriesACLTransition st2 = db.storeSeriesAclTransition(ORG, "uuid-series", new Date(1347000900000L), macl.getId(), false, Option.<ConfiguredWorkflowRef>none());
SeriesACLTransition st3 = db.storeSeriesAclTransition(ORG, "uuid-series2", new Date(1347000030000L), macl.getId(), false, option(workflow("full")));
SeriesACLTransition st4 = db.markSeriesTransitionAsCompleted(ORG, st3.getTransitionId());
EpisodeACLTransition et1 = db.storeEpisodeAclTransition(ORG, "uuid-episode", new Date(1347005303736L), Option.<Long>none(), Option.<ConfiguredWorkflowRef>none());
EpisodeACLTransition et2 = db.storeEpisodeAclTransition(ORG, "uuid-episode", new Date(1347005343736L), some(macl.getId()), Option.<ConfiguredWorkflowRef>none());
EpisodeACLTransition et3 = db.storeEpisodeAclTransition(ORG, "uuid-episode2", new Date(1347005343736L), some(macl.getId()), option(workflow("full")));
EpisodeACLTransition et4 = db.markEpisodeTransitionAsCompleted(ORG, et3.getTransitionId());
// Test All
TransitionQuery query = TransitionQuery.query();
TransitionResult result = db.getByQuery(ORG, query);
assertEquals(3, result.getEpisodeTransistions().size());
assertEquals(3, result.getSeriesTransistions().size());
assertEquals(et1.getTransitionId(), result.getEpisodeTransistions().get(0).getTransitionId());
assertEquals(et2.getTransitionId(), result.getEpisodeTransistions().get(1).getTransitionId());
assertEquals(et4.getTransitionId(), result.getEpisodeTransistions().get(2).getTransitionId());
assertEquals(st1.getTransitionId(), result.getSeriesTransistions().get(0).getTransitionId());
assertEquals(st4.getTransitionId(), result.getSeriesTransistions().get(1).getTransitionId());
assertEquals(st2.getTransitionId(), result.getSeriesTransistions().get(2).getTransitionId());
// Test Episode
query.withScope(AclScope.Episode);
result = db.getByQuery(ORG, query);
assertEquals(3, result.getEpisodeTransistions().size());
assertEquals(0, result.getSeriesTransistions().size());
assertEquals(et1.getTransitionId(), result.getEpisodeTransistions().get(0).getTransitionId());
assertEquals(et2.getTransitionId(), result.getEpisodeTransistions().get(1).getTransitionId());
assertEquals(et3.getTransitionId(), result.getEpisodeTransistions().get(2).getTransitionId());
query.withScope(AclScope.Episode);
result = db.getByQuery(ORG2, query);
assertEquals(0, result.getEpisodeTransistions().size());
assertEquals(0, result.getSeriesTransistions().size());
// Test Series
query.withScope(AclScope.Series);
result = db.getByQuery(ORG, query);
assertEquals(0, result.getEpisodeTransistions().size());
assertEquals(3, result.getSeriesTransistions().size());
assertEquals(st1.getTransitionId(), result.getSeriesTransistions().get(0).getTransitionId());
assertEquals(st3.getTransitionId(), result.getSeriesTransistions().get(1).getTransitionId());
assertEquals(st2.getTransitionId(), result.getSeriesTransistions().get(2).getTransitionId());
// Test Date from
query = TransitionQuery.query().after(new Date(1347000040000L));
result = db.getByQuery(ORG, query);
assertEquals(3, result.getEpisodeTransistions().size());
assertEquals(1, result.getSeriesTransistions().size());
assertEquals(st2.getTransitionId(), result.getSeriesTransistions().get(0).getTransitionId());
// Test Date from, to
query.before(new Date(1347005313736L)).after(new Date(1347000040000L));
result = db.getByQuery(ORG, query);
assertEquals(1, result.getEpisodeTransistions().size());
assertEquals(1, result.getSeriesTransistions().size());
assertEquals(st2.getTransitionId(), result.getSeriesTransistions().get(0).getTransitionId());
assertEquals(et1.getTransitionId(), result.getEpisodeTransistions().get(0).getTransitionId());
// Test id
query = TransitionQuery.query().withId("uuid-series");
result = db.getByQuery(ORG, query);
assertEquals(0, result.getEpisodeTransistions().size());
assertEquals(2, result.getSeriesTransistions().size());
assertEquals(st1.getTransitionId(), result.getSeriesTransistions().get(0).getTransitionId());
assertEquals(st2.getTransitionId(), result.getSeriesTransistions().get(1).getTransitionId());
query = TransitionQuery.query().withId("uuid-series");
result = db.getByQuery(ORG2, query);
assertEquals(0, result.getEpisodeTransistions().size());
assertEquals(0, result.getSeriesTransistions().size());
// Test transitionId
result = db.getByQuery(ORG, TransitionQuery.query().withTransitionId(et2.getTransitionId()));
assertEquals(1, result.getEpisodeTransistions().size());
assertEquals(0, result.getSeriesTransistions().size());
assertEquals(et2.getTransitionId(), result.getEpisodeTransistions().get(0).getTransitionId());
// Test is done
query = TransitionQuery.query().withDone(false);
result = db.getByQuery(ORG, query);
assertEquals(2, result.getEpisodeTransistions().size());
assertEquals(2, result.getSeriesTransistions().size());
assertEquals(et1.getTransitionId(), result.getEpisodeTransistions().get(0).getTransitionId());
assertEquals(et2.getTransitionId(), result.getEpisodeTransistions().get(1).getTransitionId());
assertEquals(st1.getTransitionId(), result.getSeriesTransistions().get(0).getTransitionId());
assertEquals(st2.getTransitionId(), result.getSeriesTransistions().get(1).getTransitionId());
query.withDone(true);
result = db.getByQuery(ORG, query);
assertEquals(1, result.getEpisodeTransistions().size());
assertEquals(1, result.getSeriesTransistions().size());
assertEquals(et3.getTransitionId(), result.getEpisodeTransistions().get(0).getTransitionId());
assertEquals(st3.getTransitionId(), result.getSeriesTransistions().get(0).getTransitionId());
}
@Test
public void testDone() throws Exception {
EpisodeACLTransition t = db.storeEpisodeAclTransition(ORG, "episode-id", new Date(1347005303736L), none(0L), Option.<ConfiguredWorkflowRef>none());
assertEquals(1, db.getByQuery(ORG, TransitionQuery.query().withDone(false)).getEpisodeTransistions().size());
// ensure predicates are joined by "and"
assertEquals(0, db.getByQuery(ORG, TransitionQuery.query().after(new Date(1347005303736L)).withDone(true)).getEpisodeTransistions().size());
db.markEpisodeTransitionAsCompleted(ORG, t.getTransitionId());
assertEquals(0, db.getByQuery(ORG, TransitionQuery.query().withDone(false)).getEpisodeTransistions().size());
assertEquals(1, db.getByQuery(ORG, TransitionQuery.query().withDone(true)).getEpisodeTransistions().size());
}
private ManagedAcl createAcl() {
final Option<ManagedAcl> macl = aclDb.createAcl(ORG, acl, "acl");
assertTrue(macl.isSome());
return macl.get();
}
}