package org.dataone.integration.it.testImplementations;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.io.IOUtils;
import org.dataone.client.exception.ClientSideException;
import org.dataone.client.v1.itk.D1Object;
import org.dataone.client.v1.types.D1TypeBuilder;
import org.dataone.integration.ContextAwareTestCaseDataone;
import org.dataone.integration.ExampleUtilities;
import org.dataone.integration.adapters.CommonCallAdapter;
import org.dataone.integration.adapters.MNCallAdapter;
import org.dataone.integration.webTest.WebTestDescription;
import org.dataone.integration.webTest.WebTestName;
import org.dataone.service.exceptions.BaseException;
import org.dataone.service.exceptions.IdentifierNotUnique;
import org.dataone.service.exceptions.InsufficientResources;
import org.dataone.service.exceptions.InvalidRequest;
import org.dataone.service.exceptions.InvalidSystemMetadata;
import org.dataone.service.exceptions.InvalidToken;
import org.dataone.service.exceptions.NotAuthorized;
import org.dataone.service.exceptions.NotFound;
import org.dataone.service.exceptions.NotImplemented;
import org.dataone.service.exceptions.ServiceFailure;
import org.dataone.service.exceptions.UnsupportedType;
import org.dataone.service.types.v1.AccessPolicy;
import org.dataone.service.types.v1.Checksum;
import org.dataone.service.types.v1.DescribeResponse;
import org.dataone.service.types.v1.Identifier;
import org.dataone.service.types.v1.Node;
import org.dataone.service.types.v1.NodeType;
import org.dataone.service.types.v1.ObjectList;
import org.dataone.service.types.v1.Permission;
import org.dataone.service.types.v1.Subject;
import org.dataone.service.types.v2.SystemMetadata;
import org.dataone.service.types.v2.TypeFactory;
import org.junit.Test;
/**
* Contains test against the methods that accept SID {@link Identifier} parameters.
* The tests all use the setupCase* methods to set up the different PID chain
* scenarios. Then they run their respective methods and test the outcomes.
*
* The setup methods use reflection so we don't need to create over a dozen test
* methods for one API call with each of the setups.
*
* @author Andrei
*/
public abstract class SidCommonTestImplementations extends ContextAwareTestCaseDataone {
protected static final String subjectLabel = cnSubmitter;
protected final AccessPolicy policy = buildPublicReadAccessPolicy();
/**
* metacat needs time to perform indexing operations
* (these run on a separate thread)
**/
protected static final int INDEXING_TIME = 10000;
/**
* Needed for {@link #cleanUp()} after tests run.
* {@link Map} of {@link Node} to a {@link Set} of Strings of {@link Identifier} values.
* Tells us on which {@link Node} we created objects with which {@link Identifier}s.
*/
private Map> createdIDs = new HashMap>();
/**
* Returns a {@link Node} {@link Iterator}.
* Should be {@link #getCoordinatingNodeIterator()} for CN implementation
* and {@link #getMemberNodeIterator()} for MN implementation.
*/
protected abstract Iterator getNodeIterator();
/**
* Returns an array of ints that specify which test cases to try.
* This is just for debugging convenience, to easily enable/disable lots
* of tests at once.
* See the setupCNCase*
and setupMNCase*
methods
* in subclasses.
*/
protected abstract int[] getCasesToTest();
/**
* Returns the {@link SidCommonTestImplementations} subclass containing
* the setup*Case*() methods.
* This will be {@link SidMNTestImplementations} or {@link SidCNTestImplementations}.
* This is needed to call those methods through reflection
* from one place (this class), but allows us to push
* the MN/CN setup details into the MN/CN subclass.
*/
protected abstract SidCommonTestImplementations getSetupClass();
@Override
protected String getTestDescription() {
return "Tests v2 API methods common to MNs/CNs that accept SID parameters";
}
/**
* Cleans up the nodes created using the {@link #createdIDs} map.
* Since this class is no longer the test class, we can't enforce this.
* Make sure this gets called at the end of your tests if you
* don't want a lot of nonsense objects in the system.
*/
public void cleanUp() {
for( Entry> idsForNode : createdIDs.entrySet())
{
Node node = idsForNode.getKey();
CommonCallAdapter callAdapter = new CommonCallAdapter(getSession(subjectLabel), node, "v2");
for(String idStr : idsForNode.getValue()) {
Identifier id = new Identifier();
id.setValue(idStr);
try {
callAdapter.delete(null, id);
} catch (InvalidToken | ServiceFailure | NotAuthorized | NotFound | NotImplemented
| InvalidRequest | ClientSideException e) {
log.error("Unable to delete Identifier \"" + idStr + "\" on node \""
+ node.getBaseURL() + "\"", e);
}
}
}
}
/**
* Creates an identifier starting with the given prefix.
* Uses the current time in milliseconds to generate the rest of the ID.
* @param prefix the String prefix at the start of the {@link Identifier}
* @param node the {@link Node} on which the Identifier's object will be put.
* Required for clean-up after tests run.
* @return the {@link Identifier} with the given prefix
*/
protected Identifier createIdentifier(String prefix, Node node) {
try {
Thread.sleep(2); // avoid identical Identifiers
} catch (InterruptedException e) {
// I'd be surprised
}
Identifier id = new Identifier();
id.setValue(prefix + ExampleUtilities.generateIdentifier());
return id;
}
/**
* Makes sure we delete the created object during cleanUp()
* @param node the the Node from which the object will need to be deleted
* @param pid the PID of the object to delete
*/
protected void markForCleanUp(Node node, Identifier pid) {
if(!createdIDs.containsKey(node))
createdIDs.put(node, new HashSet());
Set idsForNode = createdIDs.get(node);
idsForNode.add(pid.getValue());
}
/**
* Creates a test object according to the parameters provided.
* Also allows setting the SID and the obsoletes / obsoletedBy chain.
* If obsoletesId
or obsoletedById
are set, we need to
* make multiple calls - to create() and to updateSystemMetadata() since setting
* obsoletes or obsoletedBy on system metadata on create is invalid.
*
* @param callAdapter - the adapter for the node we're creating the object on
* @param pid - the identifier for the create object
* @param sid - the series identifier for the given pid
* @param obsoletesId - an {@link Identifier} for the previous object in the chain (optional)
* @param obsoletedById an {@link Identifier} for the next object in the chain (optional)
* @return the Identifier for the created object
*/
public Identifier createTestObject(CommonCallAdapter callAdapter, Identifier pid,
Identifier sid, Identifier obsoletesId, Identifier obsoletedById) throws InvalidToken,
ServiceFailure, NotAuthorized, IdentifierNotUnique, UnsupportedType,
InsufficientResources, InvalidSystemMetadata, NotImplemented, InvalidRequest,
UnsupportedEncodingException, NotFound, ClientSideException {
String sidVal = sid == null ? "null" : sid.getValue();
String obsoletesVal = obsoletesId == null ? "null" : obsoletesId.getValue();
String obsoletedVal = obsoletedById == null ? "null" : obsoletedById.getValue();
log.info("CREATING test object... pid: " + pid.getValue()
+ " with a sid: " + sidVal
+ " obsoletes: " + obsoletesVal
+ " obsoletedBy: " + obsoletedVal);
Identifier testObjPid = null;
getSession("testRightsHolder");
Subject rightsHolder = getSubject("testRightsHolder");
try {
testObjPid = super.createTestObject(callAdapter, pid, sid, obsoletesId, obsoletedById, policy, subjectLabel, rightsHolder.getValue());
} catch (BaseException be) {
log.error("Unable to create test object. "
+ be.getMessage() + " " + be.getDescription(), be);
throw be;
}
markForCleanUp(callAdapter.getNode(), pid);
try {
Thread.sleep(INDEXING_TIME);
} catch (InterruptedException e) {}
return testObjPid;
}
/**
* For MN cases. The first object in a series can be created with
* {@link #createTestObject(CommonCallAdapter, Identifier, Identifier, Identifier, Identifier)}
* but following objects should be updated with this method, which uses MN.update().
* @throws NoSuchMethodException
*/
public Identifier updateTestObject(CommonCallAdapter callAdapter, Identifier oldPid,
Identifier newPid, Identifier sid) throws InvalidToken, ServiceFailure, NotAuthorized,
IdentifierNotUnique, UnsupportedType, InsufficientResources, InvalidSystemMetadata,
NotImplemented, InvalidRequest, NotFound, ClientSideException, IOException, NoSuchAlgorithmException,
InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
return updateTestObject(callAdapter, oldPid, newPid, sid, null);
}
/**
* For MN cases. The first object in a series can be created with
* {@link #createTestObject(CommonCallAdapter, Identifier, Identifier, Identifier, Identifier)}
* but following objects should be updated with this method, which uses MN.update().
* @throws NoSuchMethodException
*/
public Identifier updateTestObject(CommonCallAdapter callAdapter, Identifier oldPid,
Identifier newPid, Identifier sid, Identifier obsoletedBy) throws InvalidToken, ServiceFailure, NotAuthorized,
IdentifierNotUnique, UnsupportedType, InsufficientResources, InvalidSystemMetadata,
NotImplemented, InvalidRequest, NotFound, ClientSideException, IOException, NoSuchAlgorithmException,
InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
log.info("UPDATING test object... pid: " + oldPid.getValue() + " with pid: " + newPid.getValue()
+ " with a sid: " + (sid == null ? "null" : sid.getValue()));
if(callAdapter.getNodeType() == NodeType.CN)
throw new ClientSideException("Not for CN use!");
Subject subject = getSubject("testRightsHolder");
try {
subject = policy.getAllow(0).getSubject(0);
} catch (Exception e) {
e.printStackTrace();
// continue
}
MNCallAdapter mnCallAdapter = new MNCallAdapter(getSession(subjectLabel), callAdapter.getNode(), "v2");
byte[] contentBytes = ExampleUtilities.getExampleObjectOfType(DEFAULT_TEST_OBJECTFORMAT);
D1Object d1o = new D1Object(newPid, contentBytes,
D1TypeBuilder.buildFormatIdentifier(DEFAULT_TEST_OBJECTFORMAT),
subject,
D1TypeBuilder.buildNodeReference("bogusAuthoritativeNode"));
SystemMetadata sysmeta = TypeFactory.convertTypeFromType(d1o.getSystemMetadata(), SystemMetadata.class);
sysmeta.setObsoletes(oldPid);
sysmeta.setObsoletedBy(obsoletedBy);
sysmeta.setSeriesId(sid);
InputStream objectInputStream = null;
Identifier updatedPid = null;
objectInputStream = new ByteArrayInputStream(contentBytes);
updatedPid = mnCallAdapter.update(null, oldPid, objectInputStream, newPid, sysmeta);
markForCleanUp(callAdapter.getNode(), newPid);
try {
Thread.sleep(INDEXING_TIME);
} catch (InterruptedException e) {}
return updatedPid;
}
/**
* Sets up each pid chain scenario, then calls getSystemMetadata() with the
* SID and asserts that the returned metadata's identifier matches the PID we expect.
*/
@WebTestName("getSystemMetadata: tests that getSystemMetadata works if given a SID")
@WebTestDescription("this test checks if calling getSystemMetadata with a SID "
+ "yields metadata that points to the expected head PID")
@Test
public void testGetSystemMetadata() {
log.info("Testing getSystemMetadata() method ... ");
int[] casesToTest = getCasesToTest();
for (int i = 0; i < casesToTest.length; i++) {
int caseNum = casesToTest[i];
log.info("Testing getSystemMetadata(), Case" + caseNum);
Iterator nodeIter = getNodeIterator();
while (nodeIter.hasNext()) {
Node node = nodeIter.next();
CommonCallAdapter callAdapter = new CommonCallAdapter(getSession(subjectLabel), node, "v2");
String setupMethodName = "setup" + node.getType() + "Case" + caseNum;
try {
Method setupMethod = getSetupClass().getClass().getDeclaredMethod(setupMethodName, CommonCallAdapter.class, Node.class);
IdPair idPair = (IdPair) setupMethod.invoke(getSetupClass(), callAdapter, node);
Identifier sid = idPair.sid;
Identifier pid = idPair.headPid;
Thread.sleep(INDEXING_TIME);
SystemMetadata sysMeta = callAdapter.getSystemMetadata(null, sid);
Identifier fetchedID = sysMeta.getIdentifier();
assertTrue("getSystemMetaData() Case " + caseNum + " : identifier in "
+ "sysmeta fetched by the sid should be the head pid ",
fetchedID.equals(pid));
} catch (BaseException e) {
e.printStackTrace();
handleFail(callAdapter.getNodeBaseServiceUrl(), "Case: " + i + " : " + e.getDescription());
} catch (Exception e) {
e.printStackTrace();
handleFail(callAdapter.getNodeBaseServiceUrl(), "Case: " + i + " : " + e.getMessage() + (e.getCause() == null ? "" : e.getCause().getMessage()));
}
}
}
}
/**
* Sets up each pid chain scenario, then calls get() with the
* SID and the PID, then asserts that the returned data streams are equal.
* (Note: This won't load entire object streams into memory to compare.)
*/
@WebTestName("get: tests that get() works if given a SID")
@WebTestDescription("this test checks that calling get() with a SID, and calling "
+ "get() with the head PID yield the exact same object")
@Test
public void testGet() {
log.info("Testing get() method ... ");
int[] casesToTest = getCasesToTest();
for (int i = 0; i < casesToTest.length; i++) {
int caseNum = casesToTest[i];
log.info("Testing get(), Case" + caseNum);
Iterator nodeIter = getNodeIterator();
while (nodeIter.hasNext()) {
Node node = nodeIter.next();
CommonCallAdapter callAdapter = new CommonCallAdapter(getSession(subjectLabel), node, "v2");
String setupMethodName = "setup" + node.getType() + "Case" + caseNum;
InputStream sidIS = null;
InputStream pidIS = null;
try {
Method setupMethod = getSetupClass().getClass().getDeclaredMethod(setupMethodName, CommonCallAdapter.class, Node.class);
IdPair idPair = (IdPair) setupMethod.invoke(getSetupClass(), callAdapter, node);
Identifier sid = idPair.sid;
Identifier pid = idPair.headPid;
sidIS = callAdapter.get(null, sid);
pidIS = callAdapter.get(null, pid);
assertTrue("get() Case " + caseNum, IOUtils.contentEquals(sidIS, pidIS));
} catch (BaseException e) {
e.printStackTrace();
handleFail(callAdapter.getNodeBaseServiceUrl(), "Case: " + i + " : " + e.getDescription());
} catch (Exception e) {
e.printStackTrace();
handleFail(callAdapter.getNodeBaseServiceUrl(), "Case: " + i + " : " + e.getMessage() + (e.getCause() == null ? "" : e.getCause().getMessage()));
} finally {
IOUtils.closeQuietly(sidIS);
IOUtils.closeQuietly(pidIS);
}
}
}
}
/**
* Sets up each pid chain scenario, then calls describe() with the
* SID and asserts that the returned data's checksum is equal to the checksum
* of the object of the head PID.
*/
@WebTestName("describe: tests that describe works if given a SID")
@WebTestDescription("this test checks that calling describe with a SID, and calling "
+ "describe with the head PID yield the same object")
@Test
public void testDescribe() {
log.info("Testing describe() method ... ");
int[] casesToTest = getCasesToTest();
for (int i = 0; i < casesToTest.length; i++) {
int caseNum = casesToTest[i];
log.info("Testing describe(), Case" + caseNum);
Iterator nodeIter = getNodeIterator();
while (nodeIter.hasNext()) {
Node node = nodeIter.next();
CommonCallAdapter callAdapter = new CommonCallAdapter(getSession(subjectLabel), node, "v2");
String setupMethodName = "setup" + node.getType() + "Case" + caseNum;
try {
Method setupMethod = getSetupClass().getClass().getDeclaredMethod(setupMethodName, CommonCallAdapter.class, Node.class);
IdPair idPair = (IdPair) setupMethod.invoke(getSetupClass(), callAdapter, node);
Identifier sid = idPair.sid;
Identifier pid = idPair.headPid;
DescribeResponse sidObjectDescription = callAdapter.describe(null, sid);
DescribeResponse pidObjectDescription = callAdapter.describe(null, pid);
Checksum sidChecksum = sidObjectDescription.getDataONE_Checksum();
Checksum pidChecksum = pidObjectDescription.getDataONE_Checksum();
assertTrue("describe() Case " + caseNum + " checksums of retrieved descriptions should be the same", sidChecksum.getValue().equals(pidChecksum.getValue()));
} catch (BaseException e) {
e.printStackTrace();
handleFail(callAdapter.getNodeBaseServiceUrl(), "Case: " + i + " : " + e.getDescription());
} catch (Exception e) {
e.printStackTrace();
handleFail(callAdapter.getNodeBaseServiceUrl(), "Case: " + i + " : " + e.getMessage() + (e.getCause() == null ? "" : e.getCause().getMessage()));
}
}
}
}
/**
* Calls create() with the PID, and the SID sitting in the {@link SystemMetadata}.
* We then do a getSystemMetadata() on the head SID and make sure we
* get back the expected metadata of the head PID.
* Note: this is a sanity check for create(), but we also
* test it a ton with all the calls during test setup.
*/
@WebTestName("create: tests that create works if given a SID in the system metadata")
@WebTestDescription("this test calls create with a PID while providing a"
+ "SID in the system metadata, then fetches the system metadata using that SID, "
+ "and makes sure the PID on the metadata is the expected one we called create with")
@Test
public void testCreate() {
log.info("Testing create() method ... ");
Iterator nodeIter = getNodeIterator();
while (nodeIter.hasNext()) {
Node node = nodeIter.next();
CommonCallAdapter callAdapter = new CommonCallAdapter(getSession(subjectLabel), node, "v2");
InputStream objectInputStream = null;
try {
Identifier pid = createIdentifier("P1", node);
Identifier sid = createIdentifier("S1", node);
byte[] contentBytes = ExampleUtilities.getExampleObjectOfType(DEFAULT_TEST_OBJECTFORMAT);
D1Object d1o = new D1Object(pid, contentBytes,
D1TypeBuilder.buildFormatIdentifier(DEFAULT_TEST_OBJECTFORMAT),
D1TypeBuilder.buildSubject(subjectLabel),
D1TypeBuilder.buildNodeReference("bogusAuthoritativeNode"));
SystemMetadata sysmeta = TypeFactory.convertTypeFromType(d1o.getSystemMetadata(), SystemMetadata.class);
sysmeta.setSeriesId(sid);
objectInputStream = new ByteArrayInputStream(contentBytes);
Identifier createdPid = callAdapter.create(null, pid, objectInputStream, sysmeta);
log.info("Testing create(), created new object: " + createdPid);
markForCleanUp(callAdapter.getNode(), createdPid);
SystemMetadata fetchedSysmeta = callAdapter.getSystemMetadata(null, sid);
assertTrue("create() metadata for sid should match what we created ",
fetchedSysmeta.getIdentifier().equals(pid));
} catch (BaseException e) {
e.printStackTrace();
handleFail(callAdapter.getNodeBaseServiceUrl(), e.getDescription());
} catch (Exception e) {
e.printStackTrace();
handleFail(callAdapter.getNodeBaseServiceUrl(), e.getMessage() + (e.getCause() == null ? "" : e.getCause().getMessage()));
}
}
}
/**
* Sets up each pid chain scenario, then calls delete() with the SID.
* This should remove the head PID. We then do a get() on the head PID
* and make sure we get back the expected {@link NotFound}
*/
@WebTestName("delete: tests that delete works if given a SID")
@WebTestDescription("this test creates a PID chain, calls delete with the SID of the chain "
+ ", then calls get() on the head PID of the created chain, and makes sure it's not found")
@Test
public void testDelete() {
log.info("Testing delete() method ... ");
int[] casesToTest = getCasesToTest();
for (int i = 0; i < casesToTest.length; i++) {
int caseNum = casesToTest[i];
log.info("Testing delete(), Case" + caseNum);
Iterator nodeIter = getNodeIterator();
while (nodeIter.hasNext()) {
Node node = nodeIter.next();
CommonCallAdapter callAdapter = new CommonCallAdapter(getSession(subjectLabel), node, "v2");
String setupMethodName = "setup" + node.getType() + "Case" + caseNum;
try {
Method setupMethod = getSetupClass().getClass().getDeclaredMethod(setupMethodName, CommonCallAdapter.class, Node.class);
IdPair idPair = (IdPair) setupMethod.invoke(getSetupClass(), callAdapter, node);
Identifier sid = idPair.sid;
Identifier pid = idPair.headPid;
Thread.sleep(INDEXING_TIME);
Identifier deletedObjectID = callAdapter.delete(null, sid);
// // delete(SID) should return the PID of deleted object
// assertTrue("testDelete(), Case " + caseNum + ", delete() should return the pid of the deleted object.", deletedObjectID.equals(pid));
boolean notFound = false;
try {
callAdapter.get(null, pid);
} catch (NotFound e) {
// expected result
notFound = true;
} catch (Exception e1) {
assertTrue("testDelete(), Case " + caseNum + ", expected NotFound "
+ "but got: " + e1.getClass().getSimpleName() + " : "
+ e1.getMessage(),false);
}
assertTrue("testDelete(), Case " + caseNum + ", object for the head pid should have been deleted by its sid.", notFound);
} catch (BaseException e) {
e.printStackTrace();
handleFail(callAdapter.getLatestRequestUrl(), "Case: " + i + " : " + e.getDescription());
} catch (Exception e) {
e.printStackTrace();
handleFail(callAdapter.getLatestRequestUrl(), "Case: " + i + " : " + e.getMessage() + (e.getCause() == null ? "" : e.getCause().getMessage()));
}
}
}
}
/**
* Sets up each pid chain scenario, then calls listObjects(), once with the PID as a filter,
* once with the SID as a filter. The former call should return 1 result, the latter
* should return an expected number based on the case we're testing.
*/
@WebTestName("listObjects: tests that archive works if given a SID")
@WebTestDescription("this test sets up different PID chain scenarios, then calls listObjects with "
+ "the head PID and with the SID, then makes sure the former returns on result and the latter "
+ "returns the expected number of results based on the chain we created")
@Test
public void testListObjects() {
log.info("Testing listObjects() method ... ");
int[] casesToTest = getCasesToTest();
for (int i = 0; i < casesToTest.length; i++) {
int caseNum = casesToTest[i];
log.info("Testing listObjects(), Case" + caseNum);
Iterator nodeIter = getNodeIterator();
while (nodeIter.hasNext()) {
Node node = nodeIter.next();
CommonCallAdapter callAdapter = new CommonCallAdapter(getSession(subjectLabel), node, "v2");
String setupMethodName = "setup" + node.getType() + "Case" + caseNum;
try {
Method setupMethod = getSetupClass().getClass().getDeclaredMethod(setupMethodName, CommonCallAdapter.class, Node.class);
IdPair idPair = (IdPair) setupMethod.invoke(getSetupClass(), callAdapter, node);
Identifier sid = idPair.sid;
Identifier pid = idPair.headPid;
Thread.sleep(INDEXING_TIME);
ObjectList pidObjList = callAdapter.listObjects(null, null, null, null, null, pid, null, null, null);
ObjectList sidObjList = callAdapter.listObjects(null, null, null, null, null, sid, null, null, null);
assertEquals("listObjects() Case " + caseNum + ", filter down to 1 pid", 1, pidObjList.getCount());
// calling listObjects() for a SID will return results for every PID under that SID
assertEquals("listObjects() Case " + caseNum, getPidsPerSid()[caseNum-1], sidObjList.getCount());
} catch (BaseException e) {
e.printStackTrace();
handleFail(callAdapter.getNodeBaseServiceUrl(), "Case: " + i + " : " + e.getDescription());
} catch (Exception e) {
e.printStackTrace();
handleFail(callAdapter.getNodeBaseServiceUrl(), "Case: " + i + " : " + e.getMessage() + (e.getCause() == null ? "" : e.getCause().getMessage()));
}
}
}
}
/**
* Returns the number of PIDs in the SID being tested,
* for each test case set up by setup*Case*() methods.
* (This is the SID returned from each of these methods.)
* Needed for {@link #testListObjects()}, and varies
* between CN/MN setup cases.
**/
protected abstract int[] getPidsPerSid();
/**
* Sets up each pid chain scenario, then calls isAuthorized() with both the SID and head PID.
* The best we can do with the result / behavior of isAuthorized() isn't quite enough to
* ensure the SID was resolved correctly to the head PID, but we do at least check that
* they either both return the same value or both throw the same exception.
*/
@WebTestName("isAuthorized: tests that isAuthorized works if given a SID")
@WebTestDescription("this test checks that calling isAuthorized for different permissions " +
" with the SID or head PID of a chain will return the same permissions")
@Test
public void testIsAuthorized() {
log.info("Testing isAuthorized() method ... ");
int[] casesToTest = getCasesToTest();
for (int i = 0; i < casesToTest.length; i++) {
int caseNum = casesToTest[i];
log.info("Testing isAuthorized(), Case" + caseNum);
Iterator nodeIter = getNodeIterator();
while (nodeIter.hasNext()) {
Node node = nodeIter.next();
CommonCallAdapter callAdapter = new CommonCallAdapter(getSession(subjectLabel), node, "v2");
String setupMethodName = "setup" + node.getType() + "Case" + caseNum;
try {
Method setupMethod = getSetupClass().getClass().getDeclaredMethod(setupMethodName, CommonCallAdapter.class, Node.class);
IdPair idPair = (IdPair) setupMethod.invoke(getSetupClass(), callAdapter, node);
Identifier sid = idPair.sid;
Identifier pid = idPair.headPid;
boolean sidRead = false, pidRead = false;
String sidReadExc = "", pidReadExc = "";
boolean sidWrite = false, pidWrite = false;
String sidWriteExc = "", pidWriteExc = "";
boolean sidChange = false, pidChange = false;
String sidChangeExc = "", pidChangeExc = "";
try {
sidRead = callAdapter.isAuthorized(null, sid, Permission.READ);
} catch (Exception e) {
sidReadExc = e.getClass().getSimpleName();
}
try {
pidRead = callAdapter.isAuthorized(null, pid, Permission.READ);
} catch (Exception e) {
pidReadExc = e.getClass().getSimpleName();
}
assertEquals("isAuthorized() Case " + caseNum + ", read permissions should match",
sidRead, pidRead);
assertEquals("isAuthorized() Case " + caseNum + ", read exceptions should match",
sidReadExc, pidReadExc);
try {
sidWrite = callAdapter.isAuthorized(null, sid, Permission.WRITE);
} catch (Exception e) {
sidWriteExc = e.getClass().getSimpleName();
}
try {
pidWrite = callAdapter.isAuthorized(null, pid, Permission.WRITE);
} catch (Exception e) {
pidWriteExc = e.getClass().getSimpleName();
}
assertEquals("isAuthorized() Case " + caseNum + ", write permissions should match",
sidWrite, pidWrite);
assertEquals("isAuthorized() Case " + caseNum + ", write exceptions should match",
sidWriteExc, pidWriteExc);
try {
sidChange = callAdapter.isAuthorized(null, sid, Permission.CHANGE_PERMISSION);
} catch (Exception e) {
sidChangeExc = e.getClass().getSimpleName();
}
try {
pidChange = callAdapter.isAuthorized(null, pid, Permission.CHANGE_PERMISSION);
} catch (Exception e) {
pidChangeExc = e.getClass().getSimpleName();
}
assertEquals("isAuthorized() Case " + caseNum + ", change permissions should match",
sidChange, pidChange);
assertEquals("isAuthorized() Case " + caseNum + ", change exceptions should match",
sidChangeExc, pidChangeExc);
// } catch (BaseException e) {
// handleFail(callAdapter.getLatestRequestUrl(), "Case: " + i + " : " + e.getMessage() + (e.getCause() == null ? "" : e.getCause().getMessage()));
} catch (Exception e) {
e.printStackTrace();
handleFail(callAdapter.getNodeBaseServiceUrl(), "Case: " + i + " : " + e.getMessage() + (e.getCause() == null ? "" : e.getCause().getMessage()));
}
}
}
}
@WebTestName("view: tests that view works if given a SID")
@WebTestDescription("this test checks that calling view() with a pid and sid "
+ "yields the same result")
@Test
public void testView() {
log.info("Testing view() method ... ");
int[] casesToTest = getCasesToTest();
for (int i = 0; i < casesToTest.length; i++) {
int caseNum = casesToTest[i];
log.info("Testing view(), Case" + caseNum);
Iterator nodeIter = getNodeIterator();
while (nodeIter.hasNext()) {
Node node = nodeIter.next();
CommonCallAdapter callAdapter = new CommonCallAdapter(getSession(subjectLabel), node, "v2");
CommonCallAdapter publicCallAdapter = new CommonCallAdapter(getSession(null), node, "v2");
String setupMethodName = "setup" + node.getType() + "Case" + caseNum;
InputStream sidView = null;
InputStream pidView = null;
try {
Method setupMethod = getSetupClass().getClass().getDeclaredMethod(setupMethodName, CommonCallAdapter.class, Node.class);
IdPair idPair = (IdPair) setupMethod.invoke(getSetupClass(), callAdapter, node);
Identifier sid = idPair.sid;
Identifier pid = idPair.headPid;
sidView = publicCallAdapter.view(null, "default", sid);
pidView = publicCallAdapter.view(null, "default", pid);
assertTrue("view() Case " + caseNum, IOUtils.contentEquals(sidView, pidView));
} catch (Exception e) {
e.printStackTrace();
handleFail(callAdapter.getNodeBaseServiceUrl(), e.getMessage() + (e.getCause() == null ? "" : e.getCause().getMessage()));
} finally {
IOUtils.closeQuietly(sidView);
IOUtils.closeQuietly(pidView);
}
}
}
}
/**
* Holds a pair of {@link Identifier}s.
* Used to store the sid and head pid it should resolve to.
*/
protected static class IdPair {
Identifier sid, headPid;
public IdPair(Identifier sid, Identifier headPid) {
this.sid = sid;
this.headPid = headPid;
log.info("Created SID (" + sid.getValue() + ") and head PID (" + headPid.getValue() + ") pair.");
}
}
}