From 9f91be45e1fbe6a1c9ec6fba614a82f7345d9c9e Mon Sep 17 00:00:00 2001 From: j2blake Date: Mon, 9 May 2011 18:17:42 +0000 Subject: [PATCH] NIHVIVO-2279 add more methods to the UserAccountsDao, with tests for the Jena implementation. --- .../vitro/webapp/dao/UserAccountsDao.java | 39 +++++ .../filtering/UserAccountsDaoFiltering.java | 15 ++ .../vitro/webapp/dao/jena/JenaBaseDao.java | 90 ++++++++++ .../webapp/dao/jena/UserAccountsDaoJena.java | 137 +++++++++++++++ .../vitro/testing/AbstractTestClass.java | 6 + .../webapp/dao/jena/JenaBaseDao_2_Test.java | 138 +++++++++++++++ .../dao/jena/UserAccountsDaoJenaTest.java | 161 ++++++++++++++++-- 7 files changed, 576 insertions(+), 10 deletions(-) create mode 100644 webapp/test/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao_2_Test.java diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/UserAccountsDao.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/UserAccountsDao.java index b787bc15c..ba00580f6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/UserAccountsDao.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/UserAccountsDao.java @@ -20,6 +20,45 @@ public interface UserAccountsDao { */ UserAccount getUserAccountByUri(String uri); + /** + * Create a new UserAccount in the model. + * + * On entry, the URI of the UserAccount should be empty. On exit, the URI + * which was created for this UserAccount will be stored in the UserAccount, + * as well as being returned by the method. + * + * Does not confirm that PermissionSet objects already exist for the + * PermissionSet URIs referenced by the UserAcocunt. + * + * @throws NullPointerException + * if the UserAccount is null. + * @throws IllegalArgumentException + * if the URI of the UserAccount is not empty. + */ + String insertUserAccount(UserAccount userAccount); + + /** + * Update the values on a UserAccount that already exists in the model. + * + * Does not confirm that PermissionSet objects already exist for the + * PermissionSet URIs referenced by the UserAcocunt. + * + * @throws NullPointerException + * if the UserAccount is null. + * @throws IllegalArgumentException + * if a UserAccount with this URI does not already exist in the + * model. + */ + void updateUserAccount(UserAccount userAccount); + + /** + * Remove the UserAccount with this URI from the model. + * + * If the URI is null, or if no UserAccount with this URI is found in the + * model, no action is taken. + */ + void deleteUserAccount(String userAccountUri); + /** * Get the PermissionSet for this URI. * diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/UserAccountsDaoFiltering.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/UserAccountsDaoFiltering.java index 4253b5093..7da3d2fc1 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/UserAccountsDaoFiltering.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/UserAccountsDaoFiltering.java @@ -32,6 +32,21 @@ public class UserAccountsDaoFiltering extends BaseFiltering implements return innerDao.getUserAccountByUri(uri); } + @Override + public String insertUserAccount(UserAccount userAccount) { + return innerDao.insertUserAccount(userAccount); + } + + @Override + public void updateUserAccount(UserAccount userAccount) { + innerDao.updateUserAccount(userAccount); + } + + @Override + public void deleteUserAccount(String userAccountUri) { + innerDao.deleteUserAccount(userAccountUri); + } + @Override public PermissionSet getPermissionSetByUri(String uri) { return innerDao.getPermissionSetByUri(uri); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao.java index 079f04aa6..fbff51849 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao.java @@ -258,6 +258,16 @@ public class JenaBaseDao extends JenaBaseDaoCon { } } + /** + * convenience method + */ + protected void addPropertyLongValue(Resource res, Property dataprop, + long value, Model model) { + if (dataprop != null) { + model.add(res, dataprop, Long.toString(value), XSDDatatype.XSDlong); + } + } + /** * convenience method for use with functional datatype properties */ @@ -318,6 +328,33 @@ public class JenaBaseDao extends JenaBaseDaoCon { } + /** + * convenience method for use with functional datatype properties + */ + protected void updatePropertyLongValue(Resource res, Property dataprop, + Long value, Model model) { + + if (dataprop != null) { + Long existingValue = null; + Statement stmt = res.getProperty(dataprop); + if (stmt != null) { + RDFNode object = stmt.getObject(); + if (object != null && object.isLiteral()) { + existingValue = ((Literal) object).getLong(); + } + } + + if (existingValue == null) { + model.add(res, dataprop, value.toString(), + XSDDatatype.XSDlong); + } else if (existingValue.longValue() != value) { + model.removeAll(res, dataprop, null); + model.add(res, dataprop, value.toString(), + XSDDatatype.XSDlong); + } + } + } + /** * convenience method */ @@ -622,6 +659,59 @@ public class JenaBaseDao extends JenaBaseDaoCon { } } + /** + * convenience method to update the value(s) of a one-to-many object + * property + * + * NOTE: this should be run from within a CriticalSection(WRITE) + */ + protected void updatePropertyResourceURIValues(Resource res, Property prop, + Collection uris, Model model) { + log.debug("updatePropertyResourceURIValues(), resource=" + + (res == null ? "null" : res.getURI()) + ", property=" + + (prop == null ? "null" : prop.getURI()) + ", uris=" + uris); + + if ((res == null) || (prop == null)) { + return; + } + + // figure existing URIs + Set existingUris = new HashSet(); + StmtIterator stmts = model.listStatements(res, prop, (RDFNode) null); + while (stmts.hasNext()) { + Statement stmt = stmts.next(); + RDFNode o = stmt.getObject(); + if (o instanceof Resource) { + existingUris.add(((Resource) o).getURI()); + } + } + + // figure which to add and which to remove + Set addingUris = new HashSet(uris); + addingUris.removeAll(existingUris); + Set removingUris = new HashSet(existingUris); + removingUris.removeAll(uris); + + // for each to remove, remove it. + for (String removeUri : removingUris) { + Resource o = model.getResource(removeUri); + model.remove(res, prop, o); + } + + // for each to add, add it, unless it is null, empty, or invalid. + for (String addUri : addingUris) { + if ((addUri != null) && (!addUri.isEmpty())) { + String badUriErrorStr = checkURI(addUri); + if (badUriErrorStr == null) { + Resource o = model.getResource(addUri); + model.add(res, prop, o); + } else { + log.warn(badUriErrorStr); + } + } + } + } + /** * convenience method for updating the RDFS label */ diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJena.java index 63548e7a5..bc6aa5560 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJena.java @@ -5,9 +5,11 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Random; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntResource; +import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.Statement; import com.hp.hpl.jena.shared.Lock; import com.hp.hpl.jena.util.iterator.ClosableIterator; @@ -16,6 +18,7 @@ import com.hp.hpl.jena.vocabulary.RDFS; import edu.cornell.mannlib.vitro.webapp.beans.PermissionSet; import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; +import edu.cornell.mannlib.vitro.webapp.dao.InsertException; import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao; /** @@ -66,6 +69,120 @@ public class UserAccountsDaoJena extends JenaBaseDao implements UserAccountsDao } } + @Override + public String insertUserAccount(UserAccount userAccount) { + if (userAccount == null) { + throw new NullPointerException("userAccount may not be null."); + } + if (!userAccount.getUri().isEmpty()) { + throw new IllegalArgumentException( + "URI of new userAccount must be empty."); + } + + OntModel model = getOntModel(); + + model.enterCriticalSection(Lock.WRITE); + try { + String userUri = getUnusedURI(); + Resource res = model.createIndividual(userUri, USERACCOUNT); + addPropertyStringValue(res, USERACCOUNT_EMAIL_ADDRESS, + userAccount.getEmailAddress(), model); + addPropertyStringValue(res, USERACCOUNT_FIRST_NAME, + userAccount.getFirstName(), model); + addPropertyStringValue(res, USERACCOUNT_LAST_NAME, + userAccount.getLastName(), model); + addPropertyStringValue(res, USERACCOUNT_MD5_PASSWORD, + userAccount.getMd5Password(), model); + addPropertyStringValue(res, USERACCOUNT_OLD_PASSWORD, + userAccount.getOldPassword(), model); + addPropertyLongValue(res, USERACCOUNT_PASSWORD_LINK_EXPIRES, + userAccount.getPasswordLinkExpires(), model); + addPropertyBooleanValue(res, USERACCOUNT_PASSWORD_CHANGE_REQUIRED, + userAccount.isPasswordChangeRequired(), model); + addPropertyIntValue(res, USERACCOUNT_LOGIN_COUNT, + userAccount.getLoginCount(), model); + if (userAccount.getStatus() != null) { + addPropertyStringValue(res, USERACCOUNT_STATUS, userAccount + .getStatus().toString(), model); + } + updatePropertyResourceURIValues(res, + USERACCOUNT_HAS_PERMISSION_SET, + userAccount.getPermissionSetUris(), model); + + userAccount.setUri(userUri); + return userUri; + } catch (InsertException e) { + log.error(e, e); + return null; + } finally { + model.leaveCriticalSection(); + } + } + + @Override + public void updateUserAccount(UserAccount userAccount) { + if (userAccount == null) { + throw new NullPointerException("userAccount may not be null."); + } + + OntModel model = getOntModel(); + + model.enterCriticalSection(Lock.WRITE); + try { + OntResource res = model.getOntResource(userAccount.getUri()); + if (res == null) { + throw new IllegalArgumentException("userAccount '" + + userAccount.getUri() + "' does not exist."); + } + + updatePropertyStringValue(res, USERACCOUNT_EMAIL_ADDRESS, + userAccount.getEmailAddress(), model); + updatePropertyStringValue(res, USERACCOUNT_FIRST_NAME, + userAccount.getFirstName(), model); + updatePropertyStringValue(res, USERACCOUNT_LAST_NAME, + userAccount.getLastName(), model); + updatePropertyStringValue(res, USERACCOUNT_MD5_PASSWORD, + userAccount.getMd5Password(), model); + updatePropertyStringValue(res, USERACCOUNT_OLD_PASSWORD, + userAccount.getOldPassword(), model); + updatePropertyLongValue(res, USERACCOUNT_PASSWORD_LINK_EXPIRES, + userAccount.getPasswordLinkExpires(), model); + updatePropertyBooleanValue(res, + USERACCOUNT_PASSWORD_CHANGE_REQUIRED, + userAccount.isPasswordChangeRequired(), model, true); + updatePropertyIntValue(res, USERACCOUNT_LOGIN_COUNT, + userAccount.getLoginCount(), model); + if (userAccount.getStatus() == null) { + updatePropertyStringValue(res, USERACCOUNT_STATUS, null, model); + } else { + updatePropertyStringValue(res, USERACCOUNT_STATUS, userAccount + .getStatus().toString(), model); + } + updatePropertyResourceURIValues(res, + USERACCOUNT_HAS_PERMISSION_SET, + userAccount.getPermissionSetUris(), model); + } finally { + model.leaveCriticalSection(); + } + } + + @Override + public void deleteUserAccount(String userAccountUri) { + if (userAccountUri == null) { + return; + } + + OntModel model = getOntModel(); + + model.enterCriticalSection(Lock.WRITE); + try { + Resource res = model.createResource(userAccountUri); + model.removeAll(res, null, null); + } finally { + model.leaveCriticalSection(); + } + } + @Override public PermissionSet getPermissionSetByUri(String uri) { if (uri == null) { @@ -120,4 +237,24 @@ public class UserAccountsDaoJena extends JenaBaseDao implements UserAccountsDao return list; } + private String getUnusedURI() throws InsertException { + String errMsg = null; + + String namespace = DEFAULT_NAMESPACE; + String uri = null; + + Random random = new Random(System.currentTimeMillis()); + for (int attempts = 0; attempts < 30; attempts++) { + int upperBound = (int) Math.pow(2, attempts + 13); + uri = namespace + ("n" + random.nextInt(upperBound)); + errMsg = getWebappDaoFactory().checkURI(uri); + if (errMsg == null) { + return uri; + } + } + + throw new InsertException("Could not create URI for individual: " + + errMsg); + } + } diff --git a/webapp/test/edu/cornell/mannlib/vitro/testing/AbstractTestClass.java b/webapp/test/edu/cornell/mannlib/vitro/testing/AbstractTestClass.java index d538bc3b5..cd54e7ee0 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/testing/AbstractTestClass.java +++ b/webapp/test/edu/cornell/mannlib/vitro/testing/AbstractTestClass.java @@ -21,6 +21,8 @@ import java.io.StringWriter; import java.io.Writer; import java.net.MalformedURLException; import java.net.URL; +import java.util.Arrays; +import java.util.HashSet; import java.util.Properties; import java.util.Set; import java.util.TreeSet; @@ -384,4 +386,8 @@ public abstract class AbstractTestClass { assertEquals(message, expected, actual); } + protected Set buildSet(T... array) { + return new HashSet(Arrays.asList(array)); + } + } diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao_2_Test.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao_2_Test.java new file mode 100644 index 000000000..a49ad273b --- /dev/null +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao_2_Test.java @@ -0,0 +1,138 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.dao.jena; + +import static org.junit.Assert.assertEquals; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.apache.log4j.Level; +import org.junit.Before; +import org.junit.Test; + +import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.rdf.model.Property; +import com.hp.hpl.jena.rdf.model.RDFNode; +import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.rdf.model.Statement; +import com.hp.hpl.jena.rdf.model.StmtIterator; + +import edu.cornell.mannlib.vitro.testing.AbstractTestClass; + +/** + * Another set of tests for JenaBaseDao. + */ +public class JenaBaseDao_2_Test extends AbstractTestClass { + private static final String NS_MINE = "http://my.namespace.edu/"; + + private static final String EMPTY_RESOURCE_URI = NS_MINE + "emptyResource"; + private static final String FULL_RESOURCE_URI = NS_MINE + "fullResource"; + + private static final String OLD_URI_1 = NS_MINE + "oldUri1"; + private static final String OLD_URI_2 = NS_MINE + "oldUri2"; + private static final String NEW_URI_1 = NS_MINE + "newUri1"; + private static final String NEW_URI_2 = NS_MINE + "newUri2"; + private static final String BOGUS_URI = "bogusUri"; + + private OntModel ontModel; + + private Property prop1; + + private Resource emptyResource; + private Resource fullResource; + + private JenaBaseDao dao; + + @Before + public void initializeThings() { + ontModel = ModelFactory.createOntologyModel(); + + prop1 = ontModel.createProperty("property1"); + + emptyResource = ontModel.createResource(EMPTY_RESOURCE_URI); + + fullResource = ontModel.createResource(FULL_RESOURCE_URI); + ontModel.createStatement(fullResource, prop1, + ontModel.createResource(OLD_URI_1)); + ontModel.createStatement(fullResource, prop1, + ontModel.createResource(OLD_URI_2)); + + WebappDaoFactoryJena wdfj = new WebappDaoFactoryJena(ontModel); + dao = new JenaBaseDao(wdfj); + } + + // ---------------------------------------------------------------------- + // tests of updatePropertyResourceURIValues() + // ---------------------------------------------------------------------- + + @Test + public void updatePropertyResourceURIValuesFromNothing() { + updateAndConfirm(emptyResource, prop1, + buildSet(NEW_URI_1, NEW_URI_2)); + } + + @Test + public void updatePropertyResourceURIValuesToNothing() { + updateAndConfirm(fullResource, prop1, Collections.emptySet()); + } + + @Test + public void updatePropertyResourceURIValuesNoChange() { + updateAndConfirm(fullResource, prop1, + buildSet(OLD_URI_1, OLD_URI_2)); + } + + @Test + public void updatePropertyResourceURIValuesReplaceSome() { + updateAndConfirm(fullResource, prop1, + buildSet(OLD_URI_1, NEW_URI_2)); + } + + @Test + public void updatePropertyResourceURIValuesReplaceAll() { + updateAndConfirm(fullResource, prop1, buildSet(NEW_URI_1)); + } + + @Test + public void updatePropertyResourceURIValuesTryToAddEmptyURI() { + Set uris = buildSet(""); + dao.updatePropertyResourceURIValues(emptyResource, prop1, uris, + ontModel); + assertExpectedUriValues("update URIs", emptyResource, prop1, + Collections. emptySet()); + } + + @Test + public void updatePropertyResourceURIValuesTryToAddInvalidURI() { + setLoggerLevel(JenaBaseDao.class, Level.ERROR); + Set uris = buildSet(BOGUS_URI); + dao.updatePropertyResourceURIValues(emptyResource, prop1, uris, + ontModel); + assertExpectedUriValues("update URIs", emptyResource, prop1, + Collections. emptySet()); + } + + // ---------------------------------------------------------------------- + // helper methods + // ---------------------------------------------------------------------- + + private void updateAndConfirm(Resource res, Property prop, Set uris) { + dao.updatePropertyResourceURIValues(res, prop, uris, ontModel); + assertExpectedUriValues("update URIs", res, prop, uris); + } + + private void assertExpectedUriValues(String message, Resource res, + Property prop, Set expectedUris) { + Set actualUris = new HashSet(); + StmtIterator stmts = ontModel.listStatements(res, prop, (RDFNode) null); + while (stmts.hasNext()) { + Statement stmt = stmts.next(); + actualUris.add(stmt.getObject().asResource().getURI()); + } + + assertEquals(message, expectedUris, actualUris); + } +} diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJenaTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJenaTest.java index 3a6cff241..e2214ae64 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJenaTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJenaTest.java @@ -4,6 +4,7 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; import java.io.IOException; import java.io.InputStream; @@ -22,6 +23,9 @@ import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntModelSpec; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.rdf.model.RDFNode; +import com.hp.hpl.jena.rdf.model.Statement; +import com.hp.hpl.jena.rdf.model.StmtIterator; import edu.cornell.mannlib.vitro.testing.AbstractTestClass; import edu.cornell.mannlib.vitro.webapp.beans.PermissionSet; @@ -37,9 +41,15 @@ public class UserAccountsDaoJenaTest extends AbstractTestClass { */ private static final String N3_DATA_FILENAME = "resources/UserAccountsDaoJenaTest.n3"; - private static final String NS_AUTH = "http://vitro.mannlib.cornell.edu/ns/vitro/authorization#"; private static final String NS_MINE = "http://vivo.mydomain.edu/individual/"; + private static final String URI_USER1 = NS_MINE + "user01"; + private static final String URI_NO_SUCH_USER = NS_MINE + "bogusUser"; + + private static final String URI_ROLE1 = NS_MINE + "role1"; + private static final String URI_ROLE2 = NS_MINE + "role2"; + private static final String URI_ROLE3 = NS_MINE + "role3"; + private OntModel ontModel; private WebappDaoFactoryJena wadf; private UserAccountsDaoJena dao; @@ -62,19 +72,18 @@ public class UserAccountsDaoJenaTest extends AbstractTestClass { @Test public void getUserAccountByUriSuccess() { - UserAccount u = dao.getUserAccountByUri(NS_MINE + "user01"); - assertEquals("uri", NS_MINE + "user01", u.getUri()); + UserAccount u = dao.getUserAccountByUri(URI_USER1); + assertEquals("uri", URI_USER1, u.getUri()); assertEquals("email", "email@able.edu", u.getEmailAddress()); assertEquals("firstName", "Zack", u.getFirstName()); assertEquals("lastName", "Roberts", u.getLastName()); assertEquals("md5Password", "garbage", u.getMd5Password()); assertEquals("oldPassword", "", u.getOldPassword()); - assertEquals("changeExpires", 0L, u.getPasswordLinkExpires()); + assertEquals("linkExpires", 0L, u.getPasswordLinkExpires()); assertEquals("changeRequired", false, u.isPasswordChangeRequired()); assertEquals("loginCount", 5, u.getLoginCount()); assertEquals("status", Status.ACTIVE, u.getStatus()); - assertEquals("permissionSetUris", - Collections.singleton(NS_MINE + "role1"), + assertEquals("permissionSetUris", Collections.singleton(URI_ROLE1), u.getPermissionSetUris()); } @@ -90,10 +99,126 @@ public class UserAccountsDaoJenaTest extends AbstractTestClass { assertNull("null result", u); } + @Test + public void insertUserAccountSuccess() { + UserAccount in = new UserAccount(); + in.setUri(""); + in.setEmailAddress("my@email.address"); + in.setFirstName("Joe"); + in.setLastName("Bagadonuts"); + in.setMd5Password("passwordHash"); + in.setOldPassword("oldHash"); + in.setPasswordLinkExpires(999966663333L); + in.setPasswordChangeRequired(true); + in.setLoginCount(42); + in.setStatus(Status.INACTIVE); + in.setPermissionSetUris(buildSet(URI_ROLE1, URI_ROLE2)); + + String newUri = dao.insertUserAccount(in); + + UserAccount u = dao.getUserAccountByUri(newUri); + assertEquals("uri", newUri, u.getUri()); + assertEquals("email", "my@email.address", u.getEmailAddress()); + assertEquals("firstName", "Joe", u.getFirstName()); + assertEquals("lastName", "Bagadonuts", u.getLastName()); + assertEquals("md5Password", "passwordHash", u.getMd5Password()); + assertEquals("oldPassword", "oldHash", u.getOldPassword()); + assertEquals("linkExpires", 999966663333L, u.getPasswordLinkExpires()); + assertEquals("changeRequired", true, u.isPasswordChangeRequired()); + assertEquals("loginCount", 42, u.getLoginCount()); + assertEquals("status", Status.INACTIVE, u.getStatus()); + assertEquals("permissionSetUris", buildSet(URI_ROLE1, URI_ROLE2), + u.getPermissionSetUris()); + } + + @Test(expected = NullPointerException.class) + public void insertUserAccountNullUserAccount() { + dao.insertUserAccount(null); + } + + @Test(expected = IllegalArgumentException.class) + public void insertUserAccountUriIsNotEmpty() { + UserAccount in = new UserAccount(); + in.setUri(NS_MINE + "XXXXXX"); + + dao.insertUserAccount(in); + } + + @Test + public void updateUserAccountSuccess() { + UserAccount up = new UserAccount(); + up.setUri(URI_USER1); + up.setEmailAddress("updatedEmail@able.edu"); + up.setFirstName("Ezekiel"); + up.setLastName("Roberts"); + up.setMd5Password("differentHash"); + up.setOldPassword("oldHash"); + up.setPasswordLinkExpires(1L); + up.setPasswordChangeRequired(false); + up.setLoginCount(43); + up.setStatus(Status.ACTIVE); + up.setPermissionSetUris(buildSet(URI_ROLE1, URI_ROLE3)); + + dao.updateUserAccount(up); + + UserAccount u = dao.getUserAccountByUri(URI_USER1); + assertEquals("uri", URI_USER1, u.getUri()); + assertEquals("email", "updatedEmail@able.edu", u.getEmailAddress()); + assertEquals("firstName", "Ezekiel", u.getFirstName()); + assertEquals("lastName", "Roberts", u.getLastName()); + assertEquals("md5Password", "differentHash", u.getMd5Password()); + assertEquals("oldPassword", "oldHash", u.getOldPassword()); + assertEquals("changeExpires", 1L, u.getPasswordLinkExpires()); + assertEquals("changeRequired", false, u.isPasswordChangeRequired()); + assertEquals("loginCount", 43, u.getLoginCount()); + assertEquals("status", Status.ACTIVE, u.getStatus()); + assertEquals("permissionSetUris", buildSet(URI_ROLE1, URI_ROLE3), + u.getPermissionSetUris()); + } + + @Test(expected = NullPointerException.class) + public void updateUserAccountNullUserAccount() { + dao.updateUserAccount(null); + } + + @Test(expected = IllegalArgumentException.class) + public void updateUserAccountDoesNotExist() { + UserAccount up = new UserAccount(); + up.setUri(NS_MINE + "XXXXXX"); + + dao.updateUserAccount(up); + } + + @Test + public void deleteUserAccountSuccess() { + dao.deleteUserAccount(URI_USER1); + StmtIterator stmts = ontModel.listStatements( + ontModel.getResource(URI_USER1), null, (RDFNode) null); + if (stmts.hasNext()) { + String message = "Expecting no statements to remain in the model, but found:\n"; + while (stmts.hasNext()) { + message += " " + formatStatement(stmts.next()) + "\n"; + } + fail(message); + } + } + + @Test + public void deleteUserAccountNullUri() { + // no complaint, no action. + dao.deleteUserAccount(null); + } + + @Test + public void deleteUserAccountDoesNotExist() { + // no complaint, no action. + dao.deleteUserAccount(URI_NO_SUCH_USER); + } + @Test public void getPermissionSetByUriSuccess() { - PermissionSet ps = dao.getPermissionSetByUri(NS_MINE + "role1"); - assertEquals("uri", NS_MINE + "role1", ps.getUri()); + PermissionSet ps = dao.getPermissionSetByUri(URI_ROLE1); + assertEquals("uri", URI_ROLE1, ps.getUri()); assertEquals("label", "Role 1", ps.getLabel()); assertEquals("permissionUris", Collections.singleton(NS_MINE + "permissionA"), @@ -119,13 +244,13 @@ public class UserAccountsDaoJenaTest extends AbstractTestClass { Set expected = new HashSet(); PermissionSet ps1 = new PermissionSet(); - ps1.setUri(NS_MINE + "role1"); + ps1.setUri(URI_ROLE1); ps1.setLabel("Role 1"); ps1.setPermissionUris(Collections.singleton(NS_MINE + "permissionA")); expected.add(ps1); PermissionSet ps2 = new PermissionSet(); - ps2.setUri(NS_MINE + "role2"); + ps2.setUri(URI_ROLE2); ps2.setLabel("Role 2"); expected.add(ps2); @@ -154,4 +279,20 @@ public class UserAccountsDaoJenaTest extends AbstractTestClass { assertEquals("all permission sets", expectedMaps, actualMaps); } + + @SuppressWarnings("unused") + private void dumpModelStatements() { + StmtIterator stmts = ontModel.listStatements(); + while (stmts.hasNext()) { + Statement stmt = stmts.next(); + System.out.println(formatStatement(stmt)); + } + } + + private String formatStatement(Statement stmt) { + return stmt.getSubject().getURI() + " ==> " + + stmt.getPredicate().getURI() + " ==> " + + stmt.getObject().toString(); + } + }