Skip to content

Commit

Permalink
Add Temporary:FullSummary support in Testkit backend (#1109) (#1114)
Browse files Browse the repository at this point in the history
  • Loading branch information
injectives authored Jan 18, 2022
1 parent ad1a312 commit 6f12e4c
Show file tree
Hide file tree
Showing 4 changed files with 292 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ public class GetFeatures implements TestkitRequest
"Temporary:DriverMaxConnectionPoolSize",
"Temporary:ConnectionAcquisitionTimeout",
"Temporary:GetConnectionPoolMetrics",
"Temporary:CypherPathAndRelationship"
"Temporary:CypherPathAndRelationship",
"Temporary:FullSummary"
) );

private static final Set<String> SYNC_FEATURES = new HashSet<>( Arrays.asList(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,22 @@
import neo4j.org.testkit.backend.messages.responses.TestkitResponse;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.neo4j.driver.Query;
import org.neo4j.driver.Result;
import org.neo4j.driver.exceptions.NoSuchRecordException;
import org.neo4j.driver.summary.InputPosition;
import org.neo4j.driver.summary.Plan;
import org.neo4j.driver.summary.ProfiledPlan;
import org.neo4j.driver.summary.QueryType;
import org.neo4j.driver.summary.SummaryCounters;

@Setter
@Getter
Expand Down Expand Up @@ -74,8 +86,50 @@ private Summary createResponse( org.neo4j.driver.summary.ResultSummary summary )
.protocolVersion( summary.server().protocolVersion() )
.agent( summary.server().agent() )
.build();
SummaryCounters summaryCounters = summary.counters();
Summary.Counters counters = Summary.Counters.builder()
.constraintsAdded( summaryCounters.constraintsAdded() )
.constraintsRemoved( summaryCounters.constraintsRemoved() )
.containsSystemUpdates( summaryCounters.containsSystemUpdates() )
.containsUpdates( summaryCounters.containsUpdates() )
.indexesAdded( summaryCounters.indexesAdded() )
.indexesRemoved( summaryCounters.indexesRemoved() )
.labelsAdded( summaryCounters.labelsAdded() )
.labelsRemoved( summaryCounters.labelsRemoved() )
.nodesCreated( summaryCounters.nodesCreated() )
.nodesDeleted( summaryCounters.nodesDeleted() )
.propertiesSet( summaryCounters.propertiesSet() )
.relationshipsCreated( summaryCounters.relationshipsCreated() )
.relationshipsDeleted( summaryCounters.relationshipsDeleted() )
.systemUpdates( summaryCounters.systemUpdates() )
.build();
Query summaryQuery = summary.query();
Summary.Query query = Summary.Query.builder()
.text( summaryQuery.text() )
.parameters( summaryQuery.parameters().asMap( Function.identity(), null ) )
.build();
List<Summary.Notification> notifications = summary.notifications().stream()
.map( s -> Summary.Notification.builder()
.code( s.code() )
.title( s.title() )
.description( s.description() )
.position( toInputPosition( s.position() ) )
.severity( s.severity() )
.build() )
.collect( Collectors.toList() );
Summary.SummaryBody data = Summary.SummaryBody.builder()
.serverInfo( serverInfo )
.counters( counters )
.query( query )
.database( summary.database().name() )
.notifications( notifications )
.plan( toPlan( summary.plan() ) )
.profile( toProfile( summary.profile() ) )
.queryType( toQueryType( summary.queryType() ) )
.resultAvailableAfter( summary.resultAvailableAfter( TimeUnit.MILLISECONDS ) == -1
? null : summary.resultAvailableAfter( TimeUnit.MILLISECONDS ) )
.resultConsumedAfter( summary.resultConsumedAfter( TimeUnit.MILLISECONDS ) == -1
? null : summary.resultConsumedAfter( TimeUnit.MILLISECONDS ) )
.build();
return Summary.builder()
.data( data )
Expand All @@ -88,4 +142,91 @@ public static class ResultConsumeBody
{
private String resultId;
}

private static Summary.InputPosition toInputPosition( InputPosition position )
{
if ( position == null )
{
return null;
}
return Summary.InputPosition.builder()
.offset( position.offset() )
.line( position.line() )
.column( position.column() )
.build();
}

private static Summary.Plan toPlan( Plan plan )
{
if ( plan == null )
{
return null;
}
Map<String,Object> args = new HashMap<>();
plan.arguments().forEach( ( key, value ) -> args.put( key, value.asObject() ) );
return Summary.Plan.builder()
.operatorType( plan.operatorType() )
.args( args )
.identifiers( plan.identifiers() )
.children( plan.children().stream()
.map( ResultConsume::toPlan )
.collect( Collectors.toList() ) )
.build();
}

private static Summary.Profile toProfile( ProfiledPlan plan )
{
if ( plan == null )
{
return null;
}
Map<String,Object> args = new HashMap<>();
plan.arguments().forEach( ( key, value ) -> args.put( key, value.asObject() ) );
return Summary.Profile.builder()
.operatorType( plan.operatorType() )
.args( args )
.identifiers( plan.identifiers() )
.dbHits( plan.dbHits() )
.rows( plan.records() )
.hasPageCacheStats( plan.hasPageCacheStats() )
.pageCacheHits( plan.pageCacheHits() )
.pageCacheMisses( plan.pageCacheMisses() )
.pageCacheHitRatio( plan.pageCacheHitRatio() )
.time( plan.time() )
.children( plan.children().stream()
.map( ResultConsume::toProfile )
.collect( Collectors.toList() ) )
.build();
}

private static String toQueryType( QueryType type )
{
if ( type == null )
{
return null;
}

String typeStr;
if ( type == QueryType.READ_ONLY )
{
typeStr = "r";
}
else if ( type == QueryType.READ_WRITE )
{
typeStr = "rw";
}
else if ( type == QueryType.WRITE_ONLY )
{
typeStr = "w";
}
else if ( type == QueryType.SCHEMA_WRITE )
{
typeStr = "s";
}
else
{
throw new IllegalStateException( "Unexpected query type" );
}
return typeStr;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,29 @@
@Getter
public class StartTest implements TestkitRequest
{
private static final Map<String,String> COMMON_SKIP_PATTERN_TO_REASON = new HashMap<>();
private static final Map<String,String> ASYNC_SKIP_PATTERN_TO_REASON = new HashMap<>();
private static final Map<String,String> REACTIVE_SKIP_PATTERN_TO_REASON = new HashMap<>();

static
{
COMMON_SKIP_PATTERN_TO_REASON.put( "^.*\\.test_invalid_query_type$", "Does not report type exception" );
COMMON_SKIP_PATTERN_TO_REASON.put( "^.*\\.test_no_notifications$", "An empty list is returned when there are no notifications" );
COMMON_SKIP_PATTERN_TO_REASON.put( "^.*\\.test_no_notification_info$", "An empty list is returned when there are no notifications" );
COMMON_SKIP_PATTERN_TO_REASON.put( "^.*\\.test_notifications_without_position$", "Null value is provided when position is absent" );
COMMON_SKIP_PATTERN_TO_REASON.put( "^.*\\.test_multiple_notifications$", "Null value is provided when position is absent" );
COMMON_SKIP_PATTERN_TO_REASON.put( "^.*\\.test_partial_summary_not_contains_system_updates$", "Contains updates because value is over zero" );
COMMON_SKIP_PATTERN_TO_REASON.put( "^.*\\.test_partial_summary_not_contains_updates$", "Contains updates because value is over zero" );
COMMON_SKIP_PATTERN_TO_REASON.put( "^.*\\.test_profile$", "Missing stats are reported with 0 value" );
COMMON_SKIP_PATTERN_TO_REASON.put( "^.*\\.test_server_info$", "Address includes domain name" );
COMMON_SKIP_PATTERN_TO_REASON.put( "^.*\\.test_partial_summary_contains_system_updates$", "Does not contain updates because value is zero" );
COMMON_SKIP_PATTERN_TO_REASON.put( "^.*\\.test_partial_summary_contains_updates$", "Does not contain updates because value is zero" );
COMMON_SKIP_PATTERN_TO_REASON.put( "^.*\\.test_supports_multi_db$", "Database is None" );

ASYNC_SKIP_PATTERN_TO_REASON.putAll( COMMON_SKIP_PATTERN_TO_REASON );
ASYNC_SKIP_PATTERN_TO_REASON.put( "^.*\\.test_should_reject_server_using_verify_connectivity_bolt_3x0$", "Does not error as expected" );

REACTIVE_SKIP_PATTERN_TO_REASON.putAll( COMMON_SKIP_PATTERN_TO_REASON );
// Current limitations (require further investigation or bug fixing)
String skipMessage = "Does not report RUN FAILURE";
REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.Routing[^.]+\\.test_should_write_successfully_on_leader_switch_using_tx_function$", skipMessage );
Expand Down Expand Up @@ -75,31 +91,26 @@ public class StartTest implements TestkitRequest
@Override
public TestkitResponse process( TestkitState testkitState )
{
return RunTest.builder().build();
return createResponse( COMMON_SKIP_PATTERN_TO_REASON );
}

@Override
public CompletionStage<TestkitResponse> processAsync( TestkitState testkitState )
{
TestkitResponse testkitResponse = ASYNC_SKIP_PATTERN_TO_REASON
.entrySet()
.stream()
.filter( entry -> data.getTestName().matches( entry.getKey() ) )
.findFirst()
.map( entry -> (TestkitResponse) SkipTest.builder()
.data( SkipTest.SkipTestBody.builder()
.reason( entry.getValue() )
.build() )
.build() )
.orElseGet( () -> RunTest.builder().build() );

TestkitResponse testkitResponse = createResponse( ASYNC_SKIP_PATTERN_TO_REASON );
return CompletableFuture.completedFuture( testkitResponse );
}

@Override
public Mono<TestkitResponse> processRx( TestkitState testkitState )
{
TestkitResponse testkitResponse = REACTIVE_SKIP_PATTERN_TO_REASON
TestkitResponse testkitResponse = createResponse( REACTIVE_SKIP_PATTERN_TO_REASON );
return Mono.fromCompletionStage( CompletableFuture.completedFuture( testkitResponse ) );
}

private TestkitResponse createResponse( Map<String,String> skipPatternToReason )
{
return skipPatternToReason
.entrySet()
.stream()
.filter( entry -> data.getTestName().matches( entry.getKey() ) )
Expand All @@ -110,8 +121,6 @@ public Mono<TestkitResponse> processRx( TestkitState testkitState )
.build() )
.build() )
.orElseGet( () -> RunTest.builder().build() );

return Mono.fromCompletionStage( CompletableFuture.completedFuture( testkitResponse ) );
}

@Setter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@

import lombok.Builder;
import lombok.Getter;
import lombok.experimental.SuperBuilder;

import java.util.List;
import java.util.Map;

import org.neo4j.driver.Value;

@Getter
@Builder
Expand All @@ -38,6 +44,24 @@ public String testkitName()
public static class SummaryBody
{
private ServerInfo serverInfo;

private Counters counters;

private Query query;

private String database;

private List<Notification> notifications;

private Plan plan;

private Profile profile;

private String queryType;

private Long resultAvailableAfter;

private Long resultConsumedAfter;
}

@Getter
Expand All @@ -50,4 +74,104 @@ public static class ServerInfo

private String agent;
}

@Getter
@Builder
public static class Counters
{
private int constraintsAdded;

private int constraintsRemoved;

private boolean containsSystemUpdates;

private boolean containsUpdates;

private int indexesAdded;

private int indexesRemoved;

private int labelsAdded;

private int labelsRemoved;

private int nodesCreated;

private int nodesDeleted;

private int propertiesSet;

private int relationshipsCreated;

private int relationshipsDeleted;

private int systemUpdates;
}

@Getter
@Builder
public static class Query
{
private String text;

private Map<String,Value> parameters;
}

@Getter
@Builder
public static class Notification
{
private String code;

private String title;

private String description;

private InputPosition position;

private String severity;
}

@Getter
@Builder
public static class InputPosition
{
private int offset;

private int line;

private int column;
}

@Getter
@SuperBuilder
public static class Plan
{
private String operatorType;

private Map<String,Object> args;

private List<String> identifiers;

private List<Plan> children;
}

@Getter
@SuperBuilder
public static class Profile extends Plan
{
private long dbHits;

private long rows;

private boolean hasPageCacheStats;

private long pageCacheHits;

private long pageCacheMisses;

private double pageCacheHitRatio;

private long time;
}
}

0 comments on commit 6f12e4c

Please sign in to comment.