/* The contents of this file are subject to the license and copyright terms
* detailed in the license directory at the root of the source tree (also
* available online at http://fedora-commons.org/license/).
*/
package org.fcrepo.test.integration.cma;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import junit.framework.Assert;
import org.fcrepo.client.FedoraClient;
import org.fcrepo.client.utility.AutoPurger;
import org.fcrepo.server.management.FedoraAPIMMTOM;
import org.fcrepo.test.FedoraServerTestCase;
import static org.fcrepo.test.integration.cma.Util.ingestTestObjects;
import static org.junit.Assert.assertTrue;
/**
* Tests for reasonable/predictable behaviour when sDeps conflict.
* <p>
* Two Service Deployment objects (SDeps) deployed simultaneously for the same
* service on the same content model creates a conflict. In general, this is a
* problem - don't do it. However, there are a few legitimate reasons for
* wanting to do so, primarily when replacing one SDep with another. Faced with
* a choice of first removing the old SDep, then replacing it vs. first
* ingesting/activating a new one, then subsequently removing the old one, we
* notice that the former situation guarantees a period of time in which there
* is no SDep for a given service - which may be problematic in situations where
* downtime is unacceptable.
* </p>
* <p>
* In order to support replacing sDeps without downtime, Fedora adopts the
* following policy: If two or more SDep objects deploy the same service for the
* same content model, then the object with the <em>earliest</em> modification
* date will be used. Thus, a newly ingested or modified SDep will have a more
* recent last modified date, and will be ignored until the existing SDep is
* purged or modified.
* </p>
* These tests verify the above behavior.
*
* @author birkland
*/
public class ConflictingDeploymentTests {
private static final String DEMO_OBJECT_BASE =
"cma-examples/conflicting-deployments";
private static final String PUBLIC_OBJECT_BASE =
DEMO_OBJECT_BASE + "/public-objects";
private static final String DEPLOYMENT_1_BASE =
DEMO_OBJECT_BASE + "/sdeps/1";
private static final String DEPLOYMENT_2_BASE =
DEMO_OBJECT_BASE + "/sdeps/2";
private final String SDEF_PID = "demo:conflicting-deployment.sdef";
private final String OBJECT_PID = "demo:conflicting-deployment.object";
private final String SDEP_1_PID = "demo:conflicting-deployment.sdep1";
private final String SDEP_2_PID = "demo:conflicting-deployment.sdep2";
private final String METHOD_NAME = "content";
private static FedoraClient s_client;
public static junit.framework.Test suite() {
return new junit.framework.JUnit4TestAdapter(ConflictingDeploymentTests.class);
}
@BeforeClass
public static void bootStrap() throws Exception {
s_client =
new FedoraClient(FedoraServerTestCase.getBaseURL(),
FedoraServerTestCase.getUsername(),
FedoraServerTestCase.getPassword());
ingestTestObjects(s_client, PUBLIC_OBJECT_BASE);
}
@AfterClass
public static void cleanUp() {
s_client.shutdown();
}
@Before
public void setUp() throws Exception {
int ingested = 0;
ingested = ingestTestObjects(s_client, DEPLOYMENT_1_BASE);
assertTrue("No objects were ingested from " + Util.resourcePath(DEPLOYMENT_1_BASE), ingested > 0);
ingested = ingestTestObjects(s_client, DEPLOYMENT_2_BASE);
assertTrue("No objects were ingested from " + Util.resourcePath(DEPLOYMENT_2_BASE), ingested > 0);
}
@After
public void tearDown() throws Exception {
FedoraAPIMMTOM apim = s_client.getAPIMMTOM();
AutoPurger.purge(apim, SDEP_1_PID, null);
AutoPurger.purge(apim, SDEP_2_PID, null);
}
/**
* If two sDeps are ingested, the first one ingested should be the one to
* drive the dissemination. Ingest in order 1,2
*/
@Test
public void testDeployFirstIngested12() throws Exception {
String content = getDisseminatedContent();
Assert.assertFalse("Wrong deployment used!" + content, content
.contains("CONTENT_2"));
Assert.assertTrue("Did not disseminate expected content", content
.contains("CONTENT_1"));
}
/**
* If two sDeps are ingested, the first one ingested should be the one to
* drive the dissemination. Ingest in order 2,1
*/
@Test
public void testDeployFirstIngested21() throws Exception {
String content = getDisseminatedContent();
Assert.assertFalse("Wrong deployment used!", content
.contains("CONTENT_2"));
Assert.assertTrue("Did not disseminate expected content", content
.contains("CONTENT_1"));
}
/**
* Modifying the oldest SDep will make it the newest, thus switching the
* SDep used.
*/
@Test
public void testModifyOldestSdep() throws Exception {
modify(SDEP_1_PID);
String content = getDisseminatedContent();
/* Now deployment 2 should be oldest */
Assert.assertFalse("Wrong deployment used!", content
.contains("CONTENT_1"));
Assert.assertTrue("Did not disseminate expected content", content
.contains("CONTENT_2"));
}
/**
* Modifying the newest SDep should have no effect
*/
@Test
public void testModifyNewestSdep() throws Exception {
modify(SDEP_2_PID);
String content = getDisseminatedContent();
/* Now deployment 2 should be oldest */
Assert.assertFalse("Wrong deployment used!", content
.contains("CONTENT_2"));
Assert.assertTrue("Did not disseminate expected content", content
.contains("CONTENT_1"));
}
/**
* Represents the most likely case. Should pass with flying colours.
*/
@Test
public void testPurgeReplace() throws Exception {
s_client.getAPIMMTOM()
.purgeObject(SDEP_1_PID, "removing first sDep", false);
try{
Assert.assertTrue("Did not disseminate expected content: ",
getDisseminatedContent().contains("CONTENT_2"));
} finally {
// this object is re-ingested here solely because the cleanup/purge
// can't handle the potentially missing item
ingestTestObjects(s_client, DEPLOYMENT_1_BASE);
}
}
private void modify(String pid) throws Exception {
s_client.getAPIMMTOM().addRelationship(pid,
"http://example.org/isModified",
"true",
true,
null);
}
private String getDisseminatedContent() throws Exception {
return Util.getDissemination(s_client,
OBJECT_PID,
SDEF_PID,
METHOD_NAME);
}
}