MetadataExtractor { public ResultSummary extractSummary(Query query, Connection connection, long resultAvailableAfter, Map<String,Value> metadata ) { ServerInfo serverInfo = new InternalServerInfo( connection.serverAddress(), connection.serverVersion() ); DatabaseInfo dbInfo = extractDatabaseInfo( metadata ); return new InternalResultSummary(query, serverInfo, dbInfo, extractQueryType( metadata ), extractCounters( metadata ), extractPlan( metadata ), extractProfiledPlan( metadata ), extractNotifications( metadata ), resultAvailableAfter, extractResultConsumedAfter( metadata, resultConsumedAfterMetadataKey ) ); } MetadataExtractor( String resultAvailableAfterMetadataKey, String resultConsumedAfterMetadataKey ); QueryKeys extractQueryKeys( Map<String,Value> metadata ); long extractQueryId( Map<String,Value> metadata ); long extractResultAvailableAfter( Map<String,Value> metadata ); ResultSummary extractSummary(Query query, Connection connection, long resultAvailableAfter, Map<String,Value> metadata ); static DatabaseInfo extractDatabaseInfo( Map<String,Value> metadata ); static Bookmark extractBookmarks( Map<String,Value> metadata ); static ServerVersion extractNeo4jServerVersion( Map<String,Value> metadata ); static final int ABSENT_QUERY_ID; }
@Test void shouldBuildResultSummaryWithQuery() { Query query = new Query( "UNWIND range(10, 100) AS x CREATE (:Node {name: $name, x: x})", singletonMap( "name", "Apa" ) ); ResultSummary summary = extractor.extractSummary(query, connectionMock(), 42, emptyMap() ); assertEquals(query, summary.query() ); }
@Test void shouldBuildResultSummaryWithServerInfo() { Connection connection = connectionMock( new BoltServerAddress( "server:42" ), v4_0_0 ); ResultSummary summary = extractor.extractSummary( query(), connection, 42, emptyMap() ); assertEquals( "server:42", summary.server().address() ); assertEquals( "Neo4j/4.0.0", summary.server().version() ); }
@Test void shouldBuildResultSummaryWithCounters() { Value stats = parameters( "nodes-created", value( 42 ), "nodes-deleted", value( 4242 ), "relationships-created", value( 24 ), "relationships-deleted", value( 24 ), "properties-set", null, "labels-added", value( 5 ), "labels-removed", value( 10 ), "indexes-added", null, "indexes-removed", value( 0 ), "constraints-added", null, "constraints-removed", value( 2 ) ); Map<String,Value> metadata = singletonMap( "stats", stats ); ResultSummary summary = extractor.extractSummary( query(), connectionMock(), 42, metadata ); assertEquals( 42, summary.counters().nodesCreated() ); assertEquals( 4242, summary.counters().nodesDeleted() ); assertEquals( 24, summary.counters().relationshipsCreated() ); assertEquals( 24, summary.counters().relationshipsDeleted() ); assertEquals( 0, summary.counters().propertiesSet() ); assertEquals( 5, summary.counters().labelsAdded() ); assertEquals( 10, summary.counters().labelsRemoved() ); assertEquals( 0, summary.counters().indexesAdded() ); assertEquals( 0, summary.counters().indexesRemoved() ); assertEquals( 0, summary.counters().constraintsAdded() ); assertEquals( 2, summary.counters().constraintsRemoved() ); }
@Test void shouldBuildResultSummaryWithoutCounters() { ResultSummary summary = extractor.extractSummary( query(), connectionMock(), 42, emptyMap() ); assertEquals( EMPTY_STATS, summary.counters() ); }
@Test void shouldBuildResultSummaryWithPlan() { Value plan = value( parameters( "operatorType", "Projection", "args", parameters( "n", 42 ), "identifiers", values( "a", "b" ), "children", values( parameters( "operatorType", "AllNodeScan", "args", parameters( "x", 4242 ), "identifiers", values( "n", "t", "f" ) ) ) ) ); Map<String,Value> metadata = singletonMap( "plan", plan ); ResultSummary summary = extractor.extractSummary( query(), connectionMock(), 42, metadata ); assertTrue( summary.hasPlan() ); assertEquals( "Projection", summary.plan().operatorType() ); assertEquals( singletonMap( "n", value( 42 ) ), summary.plan().arguments() ); assertEquals( asList( "a", "b" ), summary.plan().identifiers() ); List<? extends Plan> children = summary.plan().children(); assertEquals( 1, children.size() ); Plan child = children.get( 0 ); assertEquals( "AllNodeScan", child.operatorType() ); assertEquals( singletonMap( "x", value( 4242 ) ), child.arguments() ); assertEquals( asList( "n", "t", "f" ), child.identifiers() ); assertEquals( 0, child.children().size() ); }
@Test void shouldBuildResultSummaryWithoutPlan() { ResultSummary summary = extractor.extractSummary( query(), connectionMock(), 42, emptyMap() ); assertFalse( summary.hasPlan() ); assertNull( summary.plan() ); }
@Test void shouldBuildResultSummaryWithProfiledPlan() { Value profile = value( parameters( "operatorType", "ProduceResult", "args", parameters( "a", 42 ), "identifiers", values( "a", "b" ), "rows", value( 424242 ), "dbHits", value( 242424 ), "time", value( 999 ), "children", values( parameters( "operatorType", "LabelScan", "args", parameters( "x", 1 ), "identifiers", values( "y", "z" ), "rows", value( 2 ), "dbHits", value( 4 ) ) ) ) ); Map<String,Value> metadata = singletonMap( "profile", profile ); ResultSummary summary = extractor.extractSummary( query(), connectionMock(), 42, metadata ); assertTrue( summary.hasPlan() ); assertTrue( summary.hasProfile() ); assertEquals( "ProduceResult", summary.profile().operatorType() ); assertEquals( singletonMap( "a", value( 42 ) ), summary.profile().arguments() ); assertEquals( asList( "a", "b" ), summary.profile().identifiers() ); assertEquals( 424242, summary.profile().records() ); assertEquals( 242424, summary.profile().dbHits() ); assertEquals( 999, summary.profile().time() ); assertFalse( summary.profile().hasPageCacheStats() ); assertEquals( 0, summary.profile().pageCacheHitRatio() ); assertEquals( 0, summary.profile().pageCacheMisses() ); assertEquals( 0, summary.profile().pageCacheHits() ); List<ProfiledPlan> children = summary.profile().children(); assertEquals( 1, children.size() ); ProfiledPlan child = children.get( 0 ); assertEquals( "LabelScan", child.operatorType() ); assertEquals( singletonMap( "x", value( 1 ) ), child.arguments() ); assertEquals( asList( "y", "z" ), child.identifiers() ); assertEquals( 2, child.records() ); assertEquals( 4, child.dbHits() ); }
@Test void shouldBuildResultSummaryWithoutProfiledPlan() { ResultSummary summary = extractor.extractSummary( query(), connectionMock(), 42, emptyMap() ); assertFalse( summary.hasProfile() ); assertNull( summary.profile() ); }
@Test void shouldBuildResultSummaryWithNotifications() { Value notification1 = parameters( "description", "Almost bad thing", "code", "Neo.DummyNotification", "title", "A title", "severity", "WARNING", "position", parameters( "offset", 42, "line", 4242, "column", 424242 ) ); Value notification2 = parameters( "description", "Almost good thing", "code", "Neo.GoodNotification", "title", "Good", "severity", "INFO", "position", parameters( "offset", 1, "line", 2, "column", 3 ) ); Value notifications = value( notification1, notification2 ); Map<String,Value> metadata = singletonMap( "notifications", notifications ); ResultSummary summary = extractor.extractSummary( query(), connectionMock(), 42, metadata ); assertEquals( 2, summary.notifications().size() ); Notification firstNotification = summary.notifications().get( 0 ); Notification secondNotification = summary.notifications().get( 1 ); assertEquals( "Almost bad thing", firstNotification.description() ); assertEquals( "Neo.DummyNotification", firstNotification.code() ); assertEquals( "A title", firstNotification.title() ); assertEquals( "WARNING", firstNotification.severity() ); assertEquals( new InternalInputPosition( 42, 4242, 424242 ), firstNotification.position() ); assertEquals( "Almost good thing", secondNotification.description() ); assertEquals( "Neo.GoodNotification", secondNotification.code() ); assertEquals( "Good", secondNotification.title() ); assertEquals( "INFO", secondNotification.severity() ); assertEquals( new InternalInputPosition( 1, 2, 3 ), secondNotification.position() ); }
@Test void shouldBuildResultSummaryWithoutNotifications() { ResultSummary summary = extractor.extractSummary( query(), connectionMock(), 42, emptyMap() ); assertEquals( 0, summary.notifications().size() ); }
@Test void shouldBuildResultSummaryWithResultAvailableAfter() { int value = 42_000; ResultSummary summary = extractor.extractSummary( query(), connectionMock(), value, emptyMap() ); assertEquals( 42, summary.resultAvailableAfter( TimeUnit.SECONDS ) ); assertEquals( value, summary.resultAvailableAfter( TimeUnit.MILLISECONDS ) ); }
@Test void shouldBuildResultSummaryWithResultConsumedAfter() { int value = 42_000; Map<String,Value> metadata = singletonMap( RESULT_CONSUMED_AFTER_KEY, value( value ) ); ResultSummary summary = extractor.extractSummary( query(), connectionMock(), 42, metadata ); assertEquals( 42, summary.resultConsumedAfter( TimeUnit.SECONDS ) ); assertEquals( value, summary.resultConsumedAfter( TimeUnit.MILLISECONDS ) ); }
@Test void shouldBuildResultSummaryWithoutResultConsumedAfter() { ResultSummary summary = extractor.extractSummary( query(), connectionMock(), 42, emptyMap() ); assertEquals( -1, summary.resultConsumedAfter( TimeUnit.SECONDS ) ); assertEquals( -1, summary.resultConsumedAfter( TimeUnit.MILLISECONDS ) ); }