| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| package org.apache.usergrid.persistence.graph.impl; |
| |
| |
| import java.util.Iterator; |
| import java.util.UUID; |
| |
| import org.junit.Before; |
| import org.junit.Ignore; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import org.apache.usergrid.persistence.core.guice.MigrationManagerRule; |
| import org.apache.usergrid.persistence.core.scope.ApplicationScope; |
| import org.apache.usergrid.persistence.core.test.ITRunner; |
| import org.apache.usergrid.persistence.core.test.UseModules; |
| import org.apache.usergrid.persistence.core.util.IdGenerator; |
| import org.apache.usergrid.persistence.graph.Edge; |
| import org.apache.usergrid.persistence.graph.GraphFig; |
| import org.apache.usergrid.persistence.graph.GraphManager; |
| import org.apache.usergrid.persistence.graph.GraphManagerFactory; |
| import org.apache.usergrid.persistence.graph.MarkedEdge; |
| import org.apache.usergrid.persistence.graph.guice.TestGraphModule; |
| import org.apache.usergrid.persistence.graph.impl.stage.NodeDeleteListener; |
| import org.apache.usergrid.persistence.graph.serialization.EdgeMetadataSerialization; |
| import org.apache.usergrid.persistence.graph.serialization.EdgeSerialization; |
| import org.apache.usergrid.persistence.graph.serialization.NodeSerialization; |
| import org.apache.usergrid.persistence.model.entity.Id; |
| import org.apache.usergrid.persistence.model.util.UUIDGenerator; |
| |
| import com.google.inject.Inject; |
| import com.netflix.astyanax.connectionpool.exceptions.ConnectionException; |
| |
| import static org.apache.usergrid.persistence.graph.test.util.EdgeTestUtils.createEdge; |
| import static org.apache.usergrid.persistence.graph.test.util.EdgeTestUtils.createGetByEdge; |
| import static org.apache.usergrid.persistence.graph.test.util.EdgeTestUtils.createSearchByEdge; |
| import static org.apache.usergrid.persistence.graph.test.util.EdgeTestUtils.createSearchEdge; |
| import static org.apache.usergrid.persistence.graph.test.util.EdgeTestUtils.createSearchIdType; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.when; |
| |
| |
| /** |
| * |
| * |
| */ |
| @RunWith( ITRunner.class ) |
| @UseModules( { TestGraphModule.class } ) |
| public class NodeDeleteListenerTest { |
| |
| private static final Logger logger = LoggerFactory.getLogger( NodeDeleteListenerTest.class ); |
| |
| |
| @Inject |
| @Rule |
| public MigrationManagerRule migrationManagerRule; |
| |
| |
| @Inject |
| protected NodeDeleteListener deleteListener; |
| |
| @Inject |
| protected EdgeSerialization edgeSerialization; |
| |
| @Inject |
| protected EdgeMetadataSerialization edgeMetadataSerialization; |
| |
| @Inject |
| protected NodeSerialization nodeSerialization; |
| |
| @Inject |
| protected GraphManagerFactory emf; |
| |
| @Inject |
| protected GraphFig graphFig; |
| |
| |
| protected ApplicationScope scope; |
| |
| |
| @Before |
| public void setup() { |
| scope = mock( ApplicationScope.class ); |
| |
| Id orgId = mock( Id.class ); |
| |
| when( orgId.getType() ).thenReturn( "organization" ); |
| when( orgId.getUuid() ).thenReturn( UUIDGenerator.newTimeUUID() ); |
| |
| when( scope.getApplication() ).thenReturn( orgId ); |
| } |
| |
| |
| /** |
| * Simple test case that tests a single edge and removing the node. The other target node should be removed as well |
| * since it has no other targets |
| */ |
| @Test |
| public void testNoDeletionMarked() { |
| |
| GraphManager em = emf.createEdgeManager( scope ); |
| |
| Edge edge = createEdge( "source", "test", "target" ); |
| |
| //write the edge |
| Edge last = em.writeEdge( edge ).toBlocking().last(); |
| |
| assertEquals( edge, last ); |
| |
| Id sourceNode = edge.getSourceNode(); |
| |
| |
| UUID eventTime = UUIDGenerator.newTimeUUID(); |
| |
| |
| int count = deleteListener.receive( scope, sourceNode, eventTime ).count().toBlocking().last(); |
| |
| assertEquals( "Mark was not set, no delete should be executed", 0, count ); |
| |
| |
| } |
| |
| |
| /** |
| * Simple test case that tests a single edge and removing the node. The other target node should be removed as well |
| * since it has no other targets |
| */ |
| @Test |
| public void testRemoveSourceNode() throws ConnectionException { |
| |
| GraphManager em = emf.createEdgeManager( scope ); |
| |
| Edge edge = createEdge( "source", "test", "target" ); |
| |
| //write the edge |
| Edge last = em.writeEdge( edge ).toBlocking().last(); |
| |
| |
| assertEquals( edge, last ); |
| |
| Id sourceNode = edge.getSourceNode(); |
| |
| Id targetNode = edge.getTargetNode(); |
| |
| |
| //mark the node so |
| UUID deleteEventTimestamp = UUIDGenerator.newTimeUUID(); |
| long timestamp = System.currentTimeMillis(); |
| |
| nodeSerialization.mark( scope, sourceNode, timestamp ).execute(); |
| |
| int count = deleteListener.receive( scope, sourceNode, deleteEventTimestamp ).count().toBlocking().last(); |
| |
| assertEquals( 1, count ); |
| |
| //now verify we can't get any of the info back |
| |
| long now = System.currentTimeMillis(); |
| |
| |
| Iterator<MarkedEdge> returned = edgeSerialization |
| .getEdgesFromSource( scope, createSearchByEdge( sourceNode, edge.getType(), now, null ) ); |
| |
| //no edge from source node should be returned |
| assertFalse( "No source should be returned", returned.hasNext() ); |
| |
| //validate it's not returned by the |
| |
| returned = edgeSerialization |
| .getEdgesToTarget( scope, createSearchByEdge( targetNode, edge.getType(), now, null ) ); |
| |
| assertFalse( "No target should be returned", returned.hasNext() ); |
| |
| |
| returned = edgeSerialization |
| .getEdgeVersions( scope, createGetByEdge( sourceNode, edge.getType(), targetNode, now, null ) ); |
| |
| assertFalse( "No version should be returned", returned.hasNext() ); |
| |
| //no types from source |
| |
| Iterator<String> types = |
| edgeMetadataSerialization.getEdgeTypesFromSource( scope, createSearchEdge( sourceNode, null ) ); |
| |
| assertFalse( types.hasNext() ); |
| |
| |
| //no types to target |
| |
| types = edgeMetadataSerialization.getEdgeTypesToTarget( scope, createSearchEdge( targetNode, null ) ); |
| |
| assertFalse( types.hasNext() ); |
| |
| |
| //no target types from source |
| |
| Iterator<String> idTypes = edgeMetadataSerialization |
| .getIdTypesFromSource( scope, createSearchIdType( sourceNode, edge.getType(), null ) ); |
| |
| assertFalse( idTypes.hasNext() ); |
| |
| //no source types to target |
| idTypes = edgeMetadataSerialization |
| .getIdTypesToTarget( scope, createSearchIdType( targetNode, edge.getType(), null ) ); |
| |
| assertFalse( idTypes.hasNext() ); |
| } |
| |
| |
| /** |
| * Simple test case that tests a single edge and removing the node. The source node should be removed as well |
| * since it has no other targets |
| */ |
| @Test |
| public void testRemoveTargetNode() throws ConnectionException { |
| |
| GraphManager em = emf.createEdgeManager( scope ); |
| |
| Edge edge = createEdge( "source", "test", "target" ); |
| |
| //write the edge |
| Edge last = em.writeEdge( edge ).toBlocking().last(); |
| |
| |
| assertEquals( edge, last ); |
| |
| Id sourceNode = edge.getSourceNode(); |
| |
| Id targetNode = edge.getTargetNode(); |
| |
| |
| //mark the node so |
| final long deleteBefore = System.currentTimeMillis(); |
| |
| nodeSerialization.mark( scope, targetNode, deleteBefore ).execute(); |
| |
| int count = deleteListener.receive( scope, targetNode, UUIDGenerator.newTimeUUID() ).count().toBlocking().last(); |
| |
| assertEquals( 1, count ); |
| |
| //now verify we can't get any of the info back |
| |
| long now = System.currentTimeMillis(); |
| |
| |
| Iterator<MarkedEdge> returned = edgeSerialization |
| .getEdgesFromSource( scope, createSearchByEdge( sourceNode, edge.getType(), now, null ) ); |
| |
| //no edge from source node should be returned |
| assertFalse( "No source should be returned", returned.hasNext() ); |
| |
| //validate it's not returned by the |
| |
| returned = edgeSerialization |
| .getEdgesToTarget( scope, createSearchByEdge( targetNode, edge.getType(), now, null ) ); |
| |
| assertFalse( "No target should be returned", returned.hasNext() ); |
| |
| |
| returned = edgeSerialization |
| .getEdgeVersions( scope, createGetByEdge( sourceNode, edge.getType(), targetNode, now, null ) ); |
| |
| assertFalse( "No version should be returned", returned.hasNext() ); |
| |
| //no types from source |
| |
| Iterator<String> types = |
| edgeMetadataSerialization.getEdgeTypesFromSource( scope, createSearchEdge( sourceNode, null ) ); |
| |
| assertFalse( types.hasNext() ); |
| |
| |
| //no types to target |
| |
| types = edgeMetadataSerialization.getEdgeTypesToTarget( scope, createSearchEdge( targetNode, null ) ); |
| |
| assertFalse( types.hasNext() ); |
| |
| |
| //no target types from source |
| |
| Iterator<String> idTypes = edgeMetadataSerialization |
| .getIdTypesFromSource( scope, createSearchIdType( sourceNode, edge.getType(), null ) ); |
| |
| assertFalse( idTypes.hasNext() ); |
| |
| //no source types to target |
| idTypes = edgeMetadataSerialization |
| .getIdTypesToTarget( scope, createSearchIdType( targetNode, edge.getType(), null ) ); |
| |
| assertFalse( idTypes.hasNext() ); |
| } |
| |
| |
| /** |
| * Simple test case that tests a single edge and removing the node. The other target node should be removed as well |
| * since it has no other targets |
| */ |
| @Test |
| @Ignore("Pending re-enable of delete functionality") |
| public void testMultiDelete() throws ConnectionException, InterruptedException { |
| |
| GraphManager em = emf.createEdgeManager( scope ); |
| |
| |
| //create loads of edges to easily delete. We'll keep all the types of "test" |
| final int edgeCount = graphFig.getScanPageSize() * 2; |
| Id toDelete = IdGenerator.createId( "toDelete" ); |
| final String edgeType = "test"; |
| |
| int countSaved = 0; |
| int sourceCount = 0; |
| int targetCount = 0; |
| |
| |
| for ( int i = 0; i < edgeCount; i++ ) { |
| Edge edge; |
| |
| //mix up source vs target, good for testing as well as create a lot of sub types to ensure they're removed |
| if ( i % 2 == 0 ) { |
| edge = createEdge( toDelete, edgeType, IdGenerator.createId( "target" + Math.random() ) ); |
| sourceCount++; |
| } |
| else { |
| edge = createEdge( IdGenerator.createId( "source" + Math.random() ), edgeType, toDelete ); |
| targetCount++; |
| } |
| |
| //write the edge |
| Edge last = em.writeEdge( edge ).toBlocking().last(); |
| |
| |
| assertEquals( edge, last ); |
| |
| countSaved++; |
| } |
| |
| assertEquals( edgeCount, countSaved ); |
| |
| logger.info( "Saved {} source edges", sourceCount ); |
| logger.info( "Saved {} target edges", targetCount ); |
| |
| long deleteVersion = Long.MAX_VALUE; |
| |
| nodeSerialization.mark( scope, toDelete, deleteVersion ).execute(); |
| |
| int count = deleteListener.receive( scope, toDelete, UUIDGenerator.newTimeUUID() ).count().toBlocking().last(); |
| |
| assertEquals( edgeCount, count ); |
| |
| //now verify we can't get any of the info back |
| |
| long now = System.currentTimeMillis(); |
| |
| |
| //validate it's not returned by the |
| |
| Iterator<MarkedEdge> returned = edgeSerialization.getEdgesToTarget( scope, createSearchByEdge( toDelete, edgeType, now, null ) ); |
| |
| assertFalse( "No target should be returned", returned.hasNext() ); |
| |
| returned = |
| edgeSerialization.getEdgesFromSource( scope, createSearchByEdge( toDelete, edgeType, now, null ) ); |
| |
| //no edge from source node should be returned |
| assertFalse( "No source should be returned", returned.hasNext() ); |
| |
| |
| |
| |
| //no types from source |
| |
| Iterator<String> types = |
| edgeMetadataSerialization.getEdgeTypesFromSource( scope, createSearchEdge( toDelete, null ) ); |
| |
| assertFalse( types.hasNext() ); |
| |
| |
| //no types to target |
| |
| types = edgeMetadataSerialization.getEdgeTypesToTarget( scope, createSearchEdge( toDelete, null ) ); |
| |
| assertFalse( types.hasNext() ); |
| |
| |
| //no target types from source |
| |
| Iterator<String> idTypes = |
| edgeMetadataSerialization.getIdTypesFromSource( scope, createSearchIdType( toDelete, edgeType, null ) ); |
| |
| assertFalse( idTypes.hasNext() ); |
| |
| //no source types to target |
| idTypes = edgeMetadataSerialization.getIdTypesToTarget( scope, createSearchIdType( toDelete, edgeType, null ) ); |
| |
| assertFalse( idTypes.hasNext() ); |
| } |
| } |