Skip to content

Commit

Permalink
Wait for futures to complete instead of timeouts in delete stress tests
Browse files Browse the repository at this point in the history
  • Loading branch information
MishaDemianenko committed Mar 22, 2018
1 parent 2c1985b commit 1661ef3
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 100 deletions.
Expand Up @@ -19,28 +19,25 @@
*/ */
package org.neo4j.cypher; package org.neo4j.cypher;


import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;


import java.io.IOException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;


import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Result;
import org.neo4j.graphdb.Transaction; import org.neo4j.graphdb.Transaction;
import org.neo4j.test.rule.ImpermanentDatabaseRule; import org.neo4j.test.rule.ImpermanentDatabaseRule;


import static org.junit.Assert.assertFalse;
import static org.neo4j.graphdb.Label.label; import static org.neo4j.graphdb.Label.label;


public class DeleteNodeStressIT public class DeleteNodeStressIT
{ {
private final AtomicBoolean hasFailed = new AtomicBoolean( false ); private final ExecutorService executorService = Executors.newFixedThreadPool( 10 );


@Rule @Rule
public ImpermanentDatabaseRule db = new ImpermanentDatabaseRule(); public ImpermanentDatabaseRule db = new ImpermanentDatabaseRule();
Expand All @@ -63,85 +60,74 @@ public void setup()
} }
} }


private final ExecutorService executorService = Executors.newFixedThreadPool( 10 ); @After
public void tearDown()
{
executorService.shutdown();
}


@Test @Test
public void shouldBeAbleToReturnNodesWhileDeletingNode() throws InterruptedException public void shouldBeAbleToReturnNodesWhileDeletingNode() throws InterruptedException, ExecutionException
{ {
// Given // Given
executeInThread( "MATCH (n:L {prop:42}) OPTIONAL MATCH (m:L {prop:1337}) WITH n MATCH (n) return n" ); Future query1 = executeInThread( "MATCH (n:L {prop:42}) OPTIONAL MATCH (m:L {prop:1337}) WITH n MATCH (n) return n" );
executeInThread( "MATCH (n:L {prop:42}) DELETE n" ); Future query2 = executeInThread( "MATCH (n:L {prop:42}) DELETE n" );

// When
executorService.awaitTermination( 3L, TimeUnit.SECONDS );


// Then // Then
assertFalse(hasFailed.get()); query1.get();
query2.get();
} }


@Test @Test
public void shouldBeAbleToCheckPropertiesWhileDeletingNode() throws InterruptedException public void shouldBeAbleToCheckPropertiesWhileDeletingNode() throws InterruptedException, ExecutionException
{ {
// Given // Given
executeInThread( "MATCH (n:L {prop:42}) OPTIONAL MATCH (m:L {prop:1337}) WITH n MATCH (n) RETURN exists(n.prop)" ); Future query1 = executeInThread( "MATCH (n:L {prop:42}) OPTIONAL MATCH (m:L {prop:1337}) WITH n MATCH (n) RETURN exists(n.prop)" );
executeInThread( "MATCH (n:L {prop:42}) DELETE n" ); Future query2 = executeInThread( "MATCH (n:L {prop:42}) DELETE n" );


// When // When
executorService.awaitTermination( 3L, TimeUnit.SECONDS ); query1.get();
assertFalse(hasFailed.get()); query2.get();
} }


@Test @Test
public void shouldBeAbleToRemovePropertiesWhileDeletingNode() throws InterruptedException public void shouldBeAbleToRemovePropertiesWhileDeletingNode() throws InterruptedException, ExecutionException
{ {
// Given // Given
executeInThread( "MATCH (n:L {prop:42}) OPTIONAL MATCH (m:L {prop:1337}) WITH n MATCH (n) REMOVE n.prop" ); Future query1 = executeInThread( "MATCH (n:L {prop:42}) OPTIONAL MATCH (m:L {prop:1337}) WITH n MATCH (n) REMOVE n.prop" );
executeInThread( "MATCH (n:L {prop:42}) DELETE n" ); Future query2 = executeInThread( "MATCH (n:L {prop:42}) DELETE n" );


// When // When
executorService.awaitTermination( 3L, TimeUnit.SECONDS ); query1.get();
assertFalse(hasFailed.get()); query2.get();
} }


@Test @Test
public void shouldBeAbleToSetPropertiesWhileDeletingNode() throws InterruptedException public void shouldBeAbleToSetPropertiesWhileDeletingNode() throws InterruptedException, ExecutionException
{ {
// Given // Given
executeInThread( "MATCH (n:L {prop:42}) OPTIONAL MATCH (m:L {prop:1337}) WITH n MATCH (n) SET n.foo = 'bar'" ); Future query1 = executeInThread( "MATCH (n:L {prop:42}) OPTIONAL MATCH (m:L {prop:1337}) WITH n MATCH (n) SET n.foo = 'bar'" );
executeInThread( "MATCH (n:L {prop:42}) DELETE n" ); Future query2 = executeInThread( "MATCH (n:L {prop:42}) DELETE n" );


// When // When
executorService.awaitTermination( 3L, TimeUnit.SECONDS ); query1.get();
assertFalse(hasFailed.get()); query2.get();
} }


@Test @Test
public void shouldBeAbleToCheckLabelsWhileDeleting() throws InterruptedException public void shouldBeAbleToCheckLabelsWhileDeleting() throws InterruptedException, ExecutionException
{ {
// Given // Given
executeInThread( "MATCH (n:L {prop:42}) OPTIONAL MATCH (m:L {prop:1337}) WITH n RETURN labels(n)" ); Future query1 = executeInThread( "MATCH (n:L {prop:42}) OPTIONAL MATCH (m:L {prop:1337}) WITH n RETURN labels(n)" );
executeInThread( "MATCH (n:L {prop:42}) DELETE n" ); Future query2 = executeInThread( "MATCH (n:L {prop:42}) DELETE n" );


// When // When
executorService.awaitTermination( 3L, TimeUnit.SECONDS ); query1.get();
assertFalse(hasFailed.get()); query2.get();
} }


private void executeInThread( final String query ) private Future executeInThread( final String query )
{ {
executorService.execute( () -> return executorService.submit( () -> db.execute( query ).resultAsString() );
{
Result execute = db.execute( query );
try
{
//resultAsString is good test case since it serializes labels, types, properties etc
execute.resultAsString();
}
catch ( Exception e )
{
e.printStackTrace();
hasFailed.set( true );
}
} );
} }
} }
Expand Up @@ -24,26 +24,21 @@
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;


import java.io.IOException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;


import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship; import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType; import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.Result;
import org.neo4j.graphdb.Transaction; import org.neo4j.graphdb.Transaction;
import org.neo4j.test.rule.ImpermanentDatabaseRule; import org.neo4j.test.rule.ImpermanentDatabaseRule;


import static org.junit.Assert.assertFalse;
import static org.neo4j.graphdb.Label.label; import static org.neo4j.graphdb.Label.label;


public class DeleteRelationshipStressIT public class DeleteRelationshipStressIT
{ {
private final AtomicBoolean hasFailed = new AtomicBoolean( false );
private final ExecutorService executorService = Executors.newFixedThreadPool( 10 ); private final ExecutorService executorService = Executors.newFixedThreadPool( 10 );


@Rule @Rule
Expand Down Expand Up @@ -81,84 +76,67 @@ public void tearDown()
} }


@Test @Test
public void shouldBeAbleToReturnRelsWhileDeletingRelationship() throws InterruptedException public void shouldBeAbleToReturnRelsWhileDeletingRelationship() throws InterruptedException, ExecutionException
{ {
// Given // Given
executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) OPTIONAL MATCH (:L)-[:T {prop:1337}]-(:L) WITH r MATCH ()-[r]-() return r" ); Future query1 = executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) OPTIONAL MATCH (:L)-[:T {prop:1337}]-(:L) WITH r MATCH ()-[r]-() return r" );
executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) DELETE r" ); Future query2 = executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) DELETE r" );


// When // When
executorService.awaitTermination( 3L, TimeUnit.SECONDS ); query1.get();

query2.get();
// Then
assertFalse(hasFailed.get());
} }


@Test @Test
public void shouldBeAbleToGetPropertyWhileDeletingRelationship() throws InterruptedException public void shouldBeAbleToGetPropertyWhileDeletingRelationship() throws InterruptedException, ExecutionException
{ {
// Given // Given
executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) OPTIONAL MATCH (:L)-[:T {prop:1337}]-(:L) WITH r MATCH ()-[r]-() return r.prop" ); Future query1 = executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) OPTIONAL MATCH (:L)-[:T {prop:1337}]-(:L) WITH r MATCH ()-[r]-() return r.prop" );
executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) DELETE r" ); Future query2 = executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) DELETE r" );


// When // When
executorService.awaitTermination( 3L, TimeUnit.SECONDS ); query1.get();
assertFalse(hasFailed.get()); query2.get();
} }


@Test @Test
public void shouldBeAbleToCheckPropertiesWhileDeletingRelationship() throws InterruptedException public void shouldBeAbleToCheckPropertiesWhileDeletingRelationship() throws InterruptedException, ExecutionException
{ {
// Given // Given
executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) " + Future query1 =
"OPTIONAL MATCH (:L)-[:T {prop:1337}]-(:L) WITH r MATCH ()-[r]-() return exists(r.prop)" ); executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) OPTIONAL MATCH (:L)-[:T {prop:1337}]-(:L) WITH r MATCH ()-[r]-() return exists(r.prop)" );
executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) DELETE r" ); Future query2 = executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) DELETE r" );


// When query1.get();
executorService.awaitTermination( 3L, TimeUnit.SECONDS ); query2.get();
assertFalse(hasFailed.get());
} }


@Test @Test
public void shouldBeAbleToRemovePropertiesWhileDeletingRelationship() throws InterruptedException public void shouldBeAbleToRemovePropertiesWhileDeletingRelationship() throws InterruptedException, ExecutionException
{ {
// Given // Given
executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) " + Future query1 = executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) OPTIONAL MATCH (:L)-[:T {prop:1337}]-(:L) WITH r MATCH ()-[r]-() REMOVE r.prop" );
"OPTIONAL MATCH (:L)-[:T {prop:1337}]-(:L) WITH r MATCH ()-[r]-() REMOVE r.prop" ); Future query2 = executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) DELETE r" );
executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) DELETE r" );


// When // When
executorService.awaitTermination( 3L, TimeUnit.SECONDS ); query1.get();
assertFalse(hasFailed.get()); query2.get();
} }


@Test @Test
public void shouldBeAbleToSetPropertiesWhileDeletingRelationship() throws InterruptedException public void shouldBeAbleToSetPropertiesWhileDeletingRelationship() throws InterruptedException, ExecutionException
{ {
// Given // Given
executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) " + Future query1 = executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) OPTIONAL MATCH (:L)-[:T {prop:1337}]-(:L) WITH r MATCH ()-[r]-() SET r.foo = 'bar'" );
"OPTIONAL MATCH (:L)-[:T {prop:1337}]-(:L) WITH r MATCH ()-[r]-() SET r.foo = 'bar'" ); Future query2 = executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) DELETE r" );
executeInThread( "MATCH (:L)-[r:T {prop:42}]-(:L) DELETE r" );


// When // When
executorService.awaitTermination( 3L, TimeUnit.SECONDS ); query1.get();
assertFalse(hasFailed.get()); query2.get();
} }


private void executeInThread( final String query ) private Future executeInThread( final String query )
{ {
executorService.execute( () -> return executorService.submit( () -> db.execute( query ).resultAsString() );
{
Result execute = db.execute( query );
try
{
//resultAsString is good test case since it serializes labels, types, properties etc
execute.resultAsString();
}
catch ( Exception e )
{
hasFailed.set( true );
}
} );
} }
} }

0 comments on commit 1661ef3

Please sign in to comment.