/*******************************************************************************
* Mission Control Technologies, Copyright (c) 2009-2012, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
* The MCT platform is licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0.
*
* 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.
*
* MCT includes source code licensed under additional open source licenses. See
* the MCT Open Source Licenses file included with this distribution or the About
* MCT Licenses dialog available at runtime from the MCT Help menu for additional
* information.
*******************************************************************************/
package gov.nasa.arc.mct.dbpersistence.service;
import gov.nasa.arc.mct.components.AbstractComponent;
import gov.nasa.arc.mct.components.ExtendedProperties;
import gov.nasa.arc.mct.components.JAXBModelStatePersistence;
import gov.nasa.arc.mct.components.ModelStatePersistence;
import gov.nasa.arc.mct.dbpersistence.dao.ComponentSpec;
import gov.nasa.arc.mct.dbpersistence.dao.Disciplines;
import gov.nasa.arc.mct.dbpersistence.dao.MctUsers;
import gov.nasa.arc.mct.dbpersistence.dao.Tag;
import gov.nasa.arc.mct.dbpersistence.dao.TagAssociation;
import gov.nasa.arc.mct.dbpersistence.dao.TagAssociationPK;
import gov.nasa.arc.mct.dbpersistence.dao.ViewState;
import gov.nasa.arc.mct.dbpersistence.dao.ViewStatePK;
import gov.nasa.arc.mct.platform.spi.Platform;
import gov.nasa.arc.mct.platform.spi.PlatformAccess;
import gov.nasa.arc.mct.policy.ExecutionResult;
import gov.nasa.arc.mct.policy.PolicyContext;
import gov.nasa.arc.mct.services.component.PolicyManager;
import gov.nasa.arc.mct.services.internal.component.ComponentInitializer;
import gov.nasa.arc.mct.services.internal.component.User;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class TestPersistenceServiceImpl {
private PersistenceServiceImpl serviceImpl;
private EntityManagerFactory factory;
private EntityManager em;
@Mock private Platform mockPlatform;
@Mock private PolicyManager mockPolicyManager;
@BeforeMethod
protected void setup() throws Exception {
MockitoAnnotations.initMocks(this);
Properties properties = new Properties();
properties.put("javax.persistence.jdbc.driver","org.apache.derby.jdbc.EmbeddedDriver");
properties.put("javax.persistence.jdbc.url","jdbc:derby:memory:testdb;create=true");
properties.put("hibernate.hbm2ddl.auto","create");
properties.put("hibernate.show_sql" ,"false");
properties.put("hibernate.format_sql", "true");
serviceImpl = new PersistenceServiceImpl() {
@Override
AbstractComponent newAbstractComponent(ComponentSpec cs) {
if (TestAbstractComponent.class.getName().equals(cs.getComponentType())) {
return new TestAbstractComponent();
}
return new AbstractComponent() {
};
}
};
serviceImpl.setEntityManagerProperties(properties);
Field f = PersistenceServiceImpl.class.getDeclaredField("entityManagerFactory");
f.setAccessible(true);
factory = (EntityManagerFactory) f.get(serviceImpl);
em = factory.createEntityManager();
Mockito.when(mockPlatform.getPolicyManager()).thenReturn(mockPolicyManager);
Mockito.when(mockPolicyManager.execute(Mockito.anyString(), Mockito.any(PolicyContext.class))).thenReturn(new ExecutionResult(null,true,""));
(new PlatformAccess()).setPlatform(mockPlatform);
Mockito.when(mockPlatform.getPersistenceProvider()).thenReturn(serviceImpl);
}
@AfterMethod
protected void tearDown() throws Exception {
factory.close();
(new PlatformAccess()).setPlatform(null);
}
private void createUsers(List<String> users, String group) {
em.getTransaction().begin();
Disciplines d = new Disciplines();
d.setDescription("test discipline");
d.setDisciplineId(group);
em.persist(d);
for (String user:users) {
MctUsers userDao = new MctUsers();
userDao.setUserId(user);
userDao.setDisciplineId(d);
em.persist(userDao);
}
em.getTransaction().commit();
}
@Test
public void testDoubleCloseOperations() {
serviceImpl.startRelatedOperations();
serviceImpl.completeRelatedOperations(true);
serviceImpl.completeRelatedOperations(true);
}
@Test
public void testAddNewUser() {
String userId = "testUser";
String sandboxId = "mysandbox";
User mockUser = Mockito.mock(User.class);
AbstractComponent mockBoxes = createAbstractComponent("Drop Boxes", "dropboxes");
Mockito.when(mockPlatform.getUserDropboxes()).thenReturn(mockBoxes);
Mockito.when(mockPlatform.getCurrentUser()).thenReturn(mockUser);
Mockito.when(mockUser.getUserId()).thenReturn(userId);
em.getTransaction().begin();
em.persist(createComponentSpec(
"dropboxes", "xyz", "123", "123", "xyz",
new ArrayList<Tag>(), Collections.<String,String>emptyMap()));
em.getTransaction().commit();
// Verify pre-condition, risk pre-populating bootstrap cache
// See https://github.com/nasa/mct/issues/245
Assert.assertEquals(serviceImpl.getBootstrapComponents().size(), 0);
serviceImpl.bind(mockPlatform);
serviceImpl.addNewUser(
userId,
"testGroup",
createAbstractComponent("My Sandbox", sandboxId , userId),
createAbstractComponent("My Dropbox", "mydropbox", userId));
Assert.assertEquals(serviceImpl.getBootstrapComponents().get(0).getComponentId(), sandboxId);
}
@Test
public void testFindComponentsByBaseDisplayedNamePattern() {
User mockUser = Mockito.mock(User.class);
Mockito.when(mockPlatform.getCurrentUser()).thenReturn(mockUser);
Mockito.when(mockUser.getUserId()).thenReturn("testUser");
String[] bdns = {
"hit 0",
"miss 0",
"hit 1",
"miss 0",
"hit 2"
};
em.getTransaction().begin();
for (int i = 0 ; i < bdns.length; i++) {
em.persist(createComponentSpec(
"search" + i,
(i==0) ? "testUser" : "otherUser",
bdns[i],
"123", "xyz",
new ArrayList<Tag>(), Collections.<String,String>emptyMap()));
}
em.getTransaction().commit();
serviceImpl.bind(mockPlatform);
Assert.assertEquals(
serviceImpl.findComponentsByBaseDisplayedNamePattern("", null).getCount(),
5);
Assert.assertEquals(
serviceImpl.findComponentsByBaseDisplayedNamePattern("hit*", null).getCount(),
3);
Assert.assertEquals(
serviceImpl.findComponentsByBaseDisplayedNamePattern("hit*", new Properties()).getCount(),
3);
Properties creatorProps = new Properties();
creatorProps.put("creator", "testUser");
Assert.assertEquals(
serviceImpl.findComponentsByBaseDisplayedNamePattern("hit*", creatorProps).getCount(),
1);
creatorProps.put("creator", "otherUser");
Assert.assertEquals(
serviceImpl.findComponentsByBaseDisplayedNamePattern("hit*", creatorProps).getCount(),
2);
}
@Test
public void testGetAllUsers() {
// setup some users
List<String> users = Arrays.asList("user1","user2","user3");
createUsers(users,"group1");
// make sure they can be retrieved
Set<String> allUsers = serviceImpl.getAllUsers();
Assert.assertEquals(allUsers.size(), users.size());
Assert.assertTrue(allUsers.containsAll(users));
}
@Test
public void testGetUsersInGroups() {
// setup some users
List<String> users = Arrays.asList("user1","user2","user3");
createUsers(users,"group1");
List<String> users2 = Arrays.asList("user12","user22");
createUsers(users2,"group2");
// make sure they can be retrieved
Collection<String> allUsers = serviceImpl.getUsersInGroup("group1");
Assert.assertEquals(allUsers.size(), users.size());
Assert.assertTrue(allUsers.containsAll(users));
allUsers = serviceImpl.getUsersInGroup("group2");
Assert.assertEquals(allUsers.size(), users2.size());
Assert.assertTrue(allUsers.containsAll(users2));
}
private ComponentSpec createComponentSpec(String id, String userId, String name, String type, String owner, List<Tag> tags, Map<String,String> views) {
ComponentSpec cs = new ComponentSpec();
cs.setComponentId(id);
cs.setCreatorUserId(userId);
cs.setComponentName(name);
cs.setComponentType(type);
cs.setOwner(owner);
cs.setReferencedComponents(new ArrayList<ComponentSpec>());
List<ViewState> viewStates = new ArrayList<ViewState>();
for (Entry<String,String> e:views.entrySet()) {
ViewState vs = new ViewState();
ViewStatePK viewStatePK = new ViewStatePK();
viewStatePK.setComponentId(cs.getComponentId());
viewStatePK.setViewType(e.getKey());
vs.setViewStatePK(viewStatePK);
vs.setViewInfo(e.getValue());
viewStates.add(vs);
}
cs.setViewStateCollection(viewStates);
cs.setTagAssociationCollection(new ArrayList<TagAssociation>());
for (Tag aTag:tags) {
TagAssociation association = new TagAssociation();
TagAssociationPK tagPK = new TagAssociationPK();
tagPK.setComponentId(cs.getComponentId());
tagPK.setTagId(aTag.getTagId());
association.setTagAssociationPK(tagPK);
association.setTagProperty(aTag.getTagProperty());
cs.getTagAssociationCollection().add(association);
}
return cs;
}
@DataProvider(name="taggedComponentTests")
Object[][] hasTaggedComponentsTestCases() {
return new Object[][] {
new Object[] {"validTag", true},
new Object[] {"invalidTag", false}
};
}
@Test(dataProvider="taggedComponentTests")
public void testHasTaggedComponents(String tag, boolean expectedResult) {
List<Tag> taggedComponents = Collections.<Tag>emptyList();
if (expectedResult) {
Tag t = new Tag();
t.setTagId(tag);
t.setTagProperty("property");
taggedComponents = Collections.singletonList(t);
}
em.getTransaction().begin();
for (Tag t:taggedComponents) {
em.persist(t);
}
em.persist(createComponentSpec("123", "xyz", "123", "123", "xyz", taggedComponents, Collections.<String,String>emptyMap()));
em.getTransaction().commit();
em.clear();
Assert.assertEquals(serviceImpl.hasComponentsTaggedBy(tag),expectedResult);
}
@Test
public void testTagComponents() {
em.getTransaction().begin();
em.persist(createComponentSpec("123", "xyz", "123", "123", "xyz", Collections.<Tag>emptyList(), Collections.<String,String>emptyMap()));
em.getTransaction().commit();
Assert.assertFalse(serviceImpl.hasComponentsTaggedBy("testTag"));
serviceImpl.tagComponents("testTag", Collections.singleton(serviceImpl.getComponent("123")));
Assert.assertTrue(serviceImpl.hasComponentsTaggedBy("testTag"));
}
public static class TestAbstractComponent extends AbstractComponent {
private AtomicReference<TestModel> model = new AtomicReference<TestModel>(new TestModel());
public void setModelValue(String v) {
model.get().setValue(v);
}
public String getModelValue() {
return model.get().getValue();
}
@Override
public String toString() {
return "compId = " + getComponentId() + " name = " + getDisplayName();
}
@Override
protected <T> T handleGetCapability(Class<T> capability) {
if (ModelStatePersistence.class.isAssignableFrom(capability)) {
JAXBModelStatePersistence<TestModel> persistence = new JAXBModelStatePersistence<TestModel>() {
@Override
protected TestModel getStateToPersist() {
return model.get();
}
@Override
protected void setPersistentState(TestModel modelState) {
model.set(modelState);
}
@Override
protected Class<TestModel> getJAXBClass() {
return TestModel.class;
}
};
return capability.cast(persistence);
}
return super.handleGetCapability(capability);
}
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public static class TestModel {
private String value;
public String getValue() {
return value;
}
public void setValue(String v) {
value = v;
}
}
private TestAbstractComponent createAbstractComponent(String componentName, String id) {
return createAbstractComponent(componentName, id, "creator");
}
private TestAbstractComponent createAbstractComponent(String componentName, String id, String creator) {
TestAbstractComponent comp = new TestAbstractComponent();
ComponentInitializer ci = comp.getCapability(ComponentInitializer.class);
ci.setId(id);
comp.setDisplayName(componentName);
comp.setModelValue(componentName);
comp.setOwner("test");
ci.setCreator(creator);
comp.save();
return comp;
}
@Test
public void testViewStateLoading() {
final TestAbstractComponent testComp = createAbstractComponent("test","0");
ExtendedProperties ep = new ExtendedProperties();
ep.addProperty("test", "abc");
testComp.getCapability(ComponentInitializer.class).setViewRoleProperty("test", ep);
serviceImpl.persist(Arrays.<AbstractComponent>asList(testComp));
Map<String, ExtendedProperties> returnedEp = serviceImpl.getAllProperties(testComp.getComponentId());
Assert.assertTrue(returnedEp.size() == 1);
Assert.assertEquals(returnedEp.get("test").getProperty("test", String.class), "abc");
}
@Test
public void testPersist() {
final TestAbstractComponent grandparent = createAbstractComponent("grandparent", "0");
final TestAbstractComponent parent = createAbstractComponent("parent", "1");
final TestAbstractComponent child = createAbstractComponent("child", "2");
List<AbstractComponent> comps = Arrays.<AbstractComponent>asList(grandparent,parent,child);
grandparent.addDelegateComponent(parent);
parent.addDelegateComponent(child);
for (AbstractComponent ac:comps) {
Assert.assertTrue(ac.isDirty());
Assert.assertNull(ac.getCreationDate());
}
serviceImpl.persist(Arrays.<AbstractComponent>asList(grandparent,parent,child));
for (AbstractComponent ac:comps) {
Assert.assertFalse(ac.isDirty());
Assert.assertNotNull(ac.getCreationDate());
}
TestAbstractComponent persistedGrandparent = (TestAbstractComponent) serviceImpl.getComponent(grandparent.getComponentId());
Assert.assertEquals(persistedGrandparent.getDisplayName(), grandparent.getDisplayName());
Assert.assertEquals(persistedGrandparent.getComponents().size(), 1, persistedGrandparent.getComponents().toString());
Assert.assertEquals(persistedGrandparent.getModelValue(), grandparent.getDisplayName());
Assert.assertEquals(persistedGrandparent.getComponents().iterator().next().getComponentId(), parent.getComponentId());
TestAbstractComponent persistedParent = (TestAbstractComponent) serviceImpl.getComponent(parent.getComponentId());
Assert.assertEquals(persistedParent.getDisplayName(), parent.getDisplayName());
Assert.assertEquals(persistedParent.getComponents().size(), 1);
Assert.assertEquals(persistedParent.getDisplayName(), persistedParent.getDisplayName());
Assert.assertEquals(persistedParent.getComponents().iterator().next().getComponentId(), child.getComponentId());
}
@Test
public void testDelete() {
em.getTransaction().begin();
final String childId = "3";
Tag t3 = new Tag();
t3.setTagId("t3");
em.persist(t3);
ComponentSpec child = createComponentSpec(childId, "xyz", "deleted", "123", "xyz", Collections.<Tag>emptyList(), Collections.<String,String>emptyMap());
ComponentSpec parent1 = createComponentSpec("1", "xyz", "parent1", "123", "xyz", Collections.<Tag>emptyList(), Collections.<String,String>emptyMap());
ComponentSpec parent2 = createComponentSpec("2", "xyz", "parent2", "123", "xyz", Collections.<Tag>emptyList(), Collections.<String,String>emptyMap());
ComponentSpec parent3 = createComponentSpec("p2", "xyz", "parent2", "123", "xyz", Collections.<Tag>singletonList(t3), Collections.<String,String>emptyMap());
List<ComponentSpec> parents = Arrays.asList(parent1,parent2);
for (ComponentSpec cs : parents) {
cs.getReferencedComponents().add(child);
}
parent3.getReferencedComponents().add(child);
em.persist(child);
em.persist(parent1);
em.persist(parent2);
em.persist(parent3);
em.getTransaction().commit();
em.clear();
int objVersion = em.find(ComponentSpec.class, "1").getObjVersion();
em.clear();
Assert.assertNotNull(em.find(Tag.class, "t3"));
AbstractComponent parent2Component = serviceImpl.getComponent("p2");
serviceImpl.delete(Collections.singleton(parent2Component));
Assert.assertNotNull(em.find(Tag.class, "t3"));
AbstractComponent deleted = serviceImpl.getComponent(child.getComponentId());
serviceImpl.delete(Collections.singleton(deleted));
Assert.assertNull(em.find(ComponentSpec.class, childId));
for (ComponentSpec cs: parents) {
ComponentSpec p = em.find(ComponentSpec.class, cs.getComponentId());
Assert.assertEquals(p.getObjVersion(), objVersion+1);
}
AbstractComponent unsavedObj = Mockito.mock(AbstractComponent.class);
Mockito.when(unsavedObj.getComponentId()).thenReturn("thisObjUnsaved");
serviceImpl.delete(Collections.singleton(unsavedObj));
}
@DataProvider(name="referencingComponents")
Object[][] referencingComponentTestCases() {
return new Object[][] {
new Object[] {Arrays.asList("1","2","3"),new Map[]{Collections.singletonMap("1", "2"), Collections.singletonMap("2", "3")}},
new Object[] {Arrays.asList("1","2","3"),new Map[0]}
};
}
@Test(dataProvider="referencingComponents")
public void testGetReferencingComponents(List<String> componentIds, Map<String,String>[] relationships) {
Map<String, List<String>> expectedRelationships = new HashMap<String, List<String>>();
// bootstrap several components
em.getTransaction().begin();
for (String id:componentIds) {
ComponentSpec cs = createComponentSpec(id, "xyz", id, "123", "xyz", Collections.<Tag>emptyList(), Collections.<String,String>emptyMap());
em.persist(cs);
}
for (Map<String,String> relation:relationships) {
for (Entry<String,String> entry:relation.entrySet()) {
ComponentSpec parent = em.find(ComponentSpec.class, entry.getKey());
ComponentSpec child = em.find(ComponentSpec.class, entry.getValue());
List<String> mappedRelationships = expectedRelationships.get(entry.getValue());
if (mappedRelationships == null) {
mappedRelationships = new ArrayList<String>();
mappedRelationships.add(entry.getKey());
expectedRelationships.put(entry.getValue(), mappedRelationships);
}
parent.getReferencedComponents().add(child);
}
}
em.getTransaction().commit();
em.clear();
// verify relationships are queried correctly
for (Entry<String,List<String>> relationshipEntries:expectedRelationships.entrySet()) {
List<String> refs = relationshipEntries.getValue();
AbstractComponent parent = Mockito.mock(AbstractComponent.class);
Mockito.when(parent.getComponentId()).thenReturn(relationshipEntries.getKey());
Collection<AbstractComponent> referencedComponents = serviceImpl.getReferences(parent);
Assert.assertEquals(referencedComponents.size(), refs.size(), "referencedComponents " + referencedComponents + "expected refs " + refs);
for (String id : refs) {
boolean found = false;
for (AbstractComponent cs:referencedComponents) {
if (cs.getComponentId().equals(id)) {
found = true;
break;
}
}
Assert.assertTrue(found, "did not find expected component in reference list");
}
}
}
}