Skip to content

Commit 1cbb616

Browse files
committed
Add support for testing full summary (#860)
1 parent 8d79dbf commit 1cbb616

File tree

5 files changed

+129
-14
lines changed

5 files changed

+129
-14
lines changed

packages/core/src/result-summary.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,9 @@ class Stats {
333333
class QueryStatistics {
334334
private _stats: Stats
335335
private _systemUpdates: number
336+
private _containsSystemUpdates?: boolean
337+
private _containsUpdates?: boolean
338+
336339
/**
337340
* Structurize the statistics
338341
* @constructor
@@ -350,7 +353,7 @@ class QueryStatistics {
350353
indexesAdded: 0,
351354
indexesRemoved: 0,
352355
constraintsAdded: 0,
353-
constraintsRemoved: 0
356+
constraintsRemoved: 0,
354357
}
355358
this._systemUpdates = 0
356359
Object.keys(statistics).forEach(index => {
@@ -360,6 +363,10 @@ class QueryStatistics {
360363
this._stats[camelCaseIndex] = intValue(statistics[index])
361364
} else if (camelCaseIndex === 'systemUpdates') {
362365
this._systemUpdates = intValue(statistics[index])
366+
} else if (camelCaseIndex === 'containsSystemUpdates') {
367+
this._containsSystemUpdates = statistics[index]
368+
} else if (camelCaseIndex === 'containsUpdates') {
369+
this._containsUpdates = statistics[index]
363370
}
364371
})
365372

@@ -371,11 +378,12 @@ class QueryStatistics {
371378
* @return {boolean}
372379
*/
373380
containsUpdates(): boolean {
374-
return (
375-
Object.keys(this._stats).reduce((last, current) => {
376-
return last + this._stats[current]
377-
}, 0) > 0
378-
)
381+
return this._containsUpdates !== undefined ?
382+
this._containsUpdates : (
383+
Object.keys(this._stats).reduce((last, current) => {
384+
return last + this._stats[current]
385+
}, 0) > 0
386+
)
379387
}
380388

381389
/**
@@ -391,7 +399,8 @@ class QueryStatistics {
391399
* @returns {boolean} - If the system database get updated or not.
392400
*/
393401
containsSystemUpdates(): boolean {
394-
return this._systemUpdates > 0
402+
return this._containsSystemUpdates !== undefined ?
403+
this._containsSystemUpdates : this._systemUpdates > 0
395404
}
396405

397406
/**

packages/testkit-backend/src/cypher-native-binders.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,33 @@ export function valueResponse (name, value) {
44
return { name: name, data: { value: value } }
55
}
66

7+
8+
export function objectToCypher (obj) {
9+
return objectMapper(obj, nativeToCypher)
10+
}
11+
12+
export function objectMemberBitIntToNumber (obj, recursive=false) {
13+
return objectMapper(obj, val => {
14+
if(typeof val === 'bigint') {
15+
return Number(val)
16+
} else if (recursive && typeof val === 'object') {
17+
return objectMemberBitIntToNumber(val)
18+
} else if (recursive && typeof val === 'array') {
19+
return val.map(item => objectMemberBitIntToNumber(item, true))
20+
}
21+
return val
22+
})
23+
}
24+
25+
function objectMapper(obj, mapper) {
26+
if (obj === null || obj === undefined) {
27+
return obj
28+
}
29+
return Object.keys(obj).reduce((acc, key) => {
30+
return {...acc, [key]: mapper(obj[key])}
31+
}, {})
32+
}
33+
734
export function nativeToCypher (x) {
835
if (x == null) {
936
return valueResponse('CypherNull', null)

packages/testkit-backend/src/request-handlers.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import neo4j from './neo4j'
22
import ResultObserver from './result-observer.js'
33
import { cypherToNative, nativeToCypher } from './cypher-native-binders.js'
4+
import { nativeToTestkitSummary } from './summary-binder.js'
45
import tls from 'tls'
56

67
const SUPPORTED_TLS = (() => {
@@ -182,18 +183,14 @@ export function ResultNext (context, data, wire) {
182183
}
183184

184185
export function ResultConsume (context, data, wire) {
186+
187+
185188
const { resultId } = data
186189
const resultObserver = context.getResultObserver(resultId)
187190
resultObserver
188191
.completitionPromise()
189192
.then(summary => {
190-
wire.writeResponse('Summary', {
191-
...summary,
192-
serverInfo: {
193-
agent: summary.server.agent,
194-
protocolVersion: summary.server.protocolVersion.toFixed(1)
195-
}
196-
})
193+
wire.writeResponse('Summary', nativeToTestkitSummary(summary))
197194
})
198195
.catch(e => wire.writeError(e))
199196
}
@@ -344,6 +341,7 @@ export function GetFeatures (_context, _params, wire) {
344341
'Temporary:ConnectionAcquisitionTimeout',
345342
'Temporary:DriverMaxConnectionPoolSize',
346343
'Temporary:FastFailingDiscovery',
344+
'Temporary:FullSummary',
347345
'Temporary:ResultKeys',
348346
'Temporary:TransactionClose',
349347
...SUPPORTED_TLS

packages/testkit-backend/src/skipped-tests/common.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,19 @@ const skippedTests = [
2727
'Not support by the JS driver',
2828
ifEquals('neo4j.sessionrun.TestSessionRun.test_partial_iteration')
2929
),
30+
skip(
31+
'Driver does not validate query type values in result summaries',
32+
ifEquals('stub.summary.test_summary.TestSummary.test_invalid_query_type')
33+
),
34+
skip(
35+
'ResultSummary.notifications defaults to empty array instead of return null/undefined',
36+
ifEquals('stub.summary.test_summary.TestSummary.test_no_notifications'),
37+
ifEquals('neo4j.test_summary.TestSummary.test_no_notification_info')
38+
),
39+
skip(
40+
'ResultSummary.plan defaults to empty array instead of return null/undefined',
41+
ifEquals('neo4j.test_summary.TestSummary.test_no_plan_info')
42+
),
3043
skip(
3144
'The driver has no support domain_name_resolver',
3245
ifEndsWith('test_should_successfully_acquire_rt_when_router_ip_changes'),
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { objectToCypher, objectMemberBitIntToNumber } from './cypher-native-binders.js'
2+
3+
function mapPlan(plan) {
4+
return {
5+
operatorType: plan.operatorType,
6+
args: plan.arguments,
7+
identifiers: plan.identifiers,
8+
children: plan.children ? plan.children.map(mapPlan) : undefined
9+
}
10+
}
11+
12+
function mapCounters(stats) {
13+
return {
14+
...stats._stats,
15+
systemUpdates: stats.systemUpdates(),
16+
containsUpdates: stats.containsUpdates(),
17+
containsSystemUpdates: stats.containsSystemUpdates()
18+
}
19+
}
20+
21+
function mapProfile(profile, child=false) {
22+
const mapChild = (child) => mapProfile(child, true)
23+
const obj = {
24+
args: objectMemberBitIntToNumber(profile.arguments),
25+
dbHits: Number(profile.dbHits),
26+
identifiers: profile.identifiers,
27+
operatorType: profile.operatorType,
28+
rows: Number(profile.rows),
29+
children: profile.children ? profile.children.map(mapChild) : undefined
30+
}
31+
32+
if (child) {
33+
return {
34+
...obj,
35+
pageCacheHitRatio: profile.pageCacheHitRatio !== undefined ? Number(profile.pageCacheHitRatio) : undefined,
36+
pageCacheHits: profile.pageCacheHits !== undefined ? Number(profile.pageCacheHits) : undefined,
37+
pageCacheMisses: profile.pageCacheMisses !== undefined ? Number(profile.pageCacheMisses) : undefined,
38+
time: profile.time !== undefined ? Number(profile.time) : undefined,
39+
}
40+
}
41+
return obj
42+
}
43+
44+
function mapNotification(notification) {
45+
return {
46+
...notification,
47+
position: Object.keys(notification.position).length !== 0 ? notification.position : undefined,
48+
}
49+
}
50+
51+
export function nativeToTestkitSummary (summary) {
52+
return {
53+
...objectMemberBitIntToNumber(summary),
54+
database: summary.database.name,
55+
query: {
56+
text: summary.query.text,
57+
parameters: objectToCypher(summary.query.parameters)
58+
},
59+
serverInfo: {
60+
agent: summary.server.agent,
61+
protocolVersion: summary.server.protocolVersion.toFixed(1)
62+
},
63+
counters: mapCounters(summary.counters),
64+
plan: mapPlan(summary.plan),
65+
profile: mapProfile(summary.profile),
66+
notifications: summary.notifications.map(mapNotification)
67+
}
68+
}

0 commit comments

Comments
 (0)