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.apache.log4j.Logger; 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.CNCallAdapter; 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.Log; import org.dataone.service.types.v2.SystemMetadata; import org.dataone.service.types.v2.TypeFactory; import org.dataone.service.util.Constants; import org.dataone.service.util.TypeMarshaller; import org.jibx.runtime.JiBXException; import org.junit.Ignore; 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.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 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 (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."); } } }