Skip to content

Commit b9d0cff

Browse files
committed
Logging cases where number will be ceiled
1 parent e475cbc commit b9d0cff

File tree

5 files changed

+199
-15
lines changed

5 files changed

+199
-15
lines changed

packages/core/src/driver.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ type CreateSession = (args: {
9898
bookmarkManager?: BookmarkManager
9999
notificationFilter?: NotificationFilter
100100
auth?: AuthToken
101+
log: Logger
101102
}) => Session
102103

103104
type CreateQueryExecutor = (createSession: (config: { database?: string, bookmarkManager?: BookmarkManager }) => Session) => QueryExecutor
@@ -827,7 +828,8 @@ class Driver {
827828
fetchSize,
828829
bookmarkManager,
829830
notificationFilter,
830-
auth
831+
auth,
832+
log: this._log
831833
})
832834
}
833835

packages/core/src/internal/tx-config.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import * as util from './util'
2121
import { newError } from '../error'
2222
import Integer, { int } from '../integer'
23+
import { Logger } from './logger'
2324

2425
/**
2526
* Internal holder of the transaction configuration.
@@ -35,9 +36,9 @@ export class TxConfig {
3536
* @constructor
3637
* @param {Object} config the raw configuration object.
3738
*/
38-
constructor (config: any) {
39+
constructor (config: any, log?: Logger) {
3940
assertValidConfig(config)
40-
this.timeout = extractTimeout(config)
41+
this.timeout = extractTimeout(config, log)
4142
this.metadata = extractMetadata(config)
4243
}
4344

@@ -63,9 +64,13 @@ const EMPTY_CONFIG = new TxConfig({})
6364
/**
6465
* @return {Integer|null}
6566
*/
66-
function extractTimeout (config: any): Integer | null {
67+
function extractTimeout (config: any, log?: Logger): Integer | null {
6768
if (util.isObject(config) && config.timeout != null) {
6869
util.assertNumberOrInteger(config.timeout, 'Transaction timeout')
70+
if (isTimeoutFloat(config) && log?.isInfoEnabled() === true) {
71+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
72+
log?.info(`Transaction timeout expected to be an integer, got: ${config.timeout}. The value will be round up.`)
73+
}
6974
const timeout = int(config.timeout, { ceilFloat: true })
7075
if (timeout.isNegative()) {
7176
throw newError('Transaction timeout should not be negative')
@@ -75,6 +80,10 @@ function extractTimeout (config: any): Integer | null {
7580
return null
7681
}
7782

83+
function isTimeoutFloat (config: any): boolean {
84+
return typeof config.timeout === 'number' && !Number.isInteger(config.timeout)
85+
}
86+
7887
/**
7988
* @return {object|null}
8089
*/

packages/core/src/session.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import ManagedTransaction from './transaction-managed'
3838
import BookmarkManager from './bookmark-manager'
3939
import { Dict } from './record'
4040
import NotificationFilter from './notification-filter'
41+
import { Logger } from './internal/logger'
4142

4243
type ConnectionConsumer = (connection: Connection | null) => any | undefined | Promise<any> | Promise<undefined>
4344
type TransactionWork<T> = (tx: Transaction) => Promise<T> | T
@@ -74,6 +75,7 @@ class Session {
7475
private readonly _results: Result[]
7576
private readonly _bookmarkManager?: BookmarkManager
7677
private readonly _notificationFilter?: NotificationFilter
78+
private readonly _log?: Logger
7779
/**
7880
* @constructor
7981
* @protected
@@ -100,7 +102,8 @@ class Session {
100102
impersonatedUser,
101103
bookmarkManager,
102104
notificationFilter,
103-
auth
105+
auth,
106+
log
104107
}: {
105108
mode: SessionMode
106109
connectionProvider: ConnectionProvider
@@ -113,6 +116,7 @@ class Session {
113116
bookmarkManager?: BookmarkManager
114117
notificationFilter?: NotificationFilter
115118
auth?: AuthToken
119+
log: Logger
116120
}) {
117121
this._mode = mode
118122
this._database = database
@@ -153,6 +157,7 @@ class Session {
153157
this._results = []
154158
this._bookmarkManager = bookmarkManager
155159
this._notificationFilter = notificationFilter
160+
this._log = log
156161
}
157162

158163
/**
@@ -176,7 +181,7 @@ class Session {
176181
parameters
177182
)
178183
const autoCommitTxConfig = (transactionConfig != null)
179-
? new TxConfig(transactionConfig)
184+
? new TxConfig(transactionConfig, this._log)
180185
: TxConfig.empty()
181186

182187
const result = this._run(validatedQuery, params, async connection => {
@@ -279,7 +284,7 @@ class Session {
279284

280285
let txConfig = TxConfig.empty()
281286
if (arg != null) {
282-
txConfig = new TxConfig(arg)
287+
txConfig = new TxConfig(arg, this._log)
283288
}
284289

285290
return this._beginTransaction(this._mode, txConfig)
@@ -385,7 +390,7 @@ class Session {
385390
transactionWork: TransactionWork<T>,
386391
transactionConfig?: TransactionConfig
387392
): Promise<T> {
388-
const config = new TxConfig(transactionConfig)
393+
const config = new TxConfig(transactionConfig, this._log)
389394
return this._runTransaction(ACCESS_MODE_READ, config, transactionWork)
390395
}
391396

@@ -410,7 +415,7 @@ class Session {
410415
transactionWork: TransactionWork<T>,
411416
transactionConfig?: TransactionConfig
412417
): Promise<T> {
413-
const config = new TxConfig(transactionConfig)
418+
const config = new TxConfig(transactionConfig, this._log)
414419
return this._runTransaction(ACCESS_MODE_WRITE, config, transactionWork)
415420
}
416421

@@ -443,7 +448,7 @@ class Session {
443448
transactionWork: ManagedTransactionWork<T>,
444449
transactionConfig?: TransactionConfig
445450
): Promise<T> {
446-
const config = new TxConfig(transactionConfig)
451+
const config = new TxConfig(transactionConfig, this._log)
447452
return this._executeInTransaction(ACCESS_MODE_READ, config, transactionWork)
448453
}
449454

@@ -465,7 +470,7 @@ class Session {
465470
transactionWork: ManagedTransactionWork<T>,
466471
transactionConfig?: TransactionConfig
467472
): Promise<T> {
468-
const config = new TxConfig(transactionConfig)
473+
const config = new TxConfig(transactionConfig, this._log)
469474
return this._executeInTransaction(ACCESS_MODE_WRITE, config, transactionWork)
470475
}
471476

packages/core/test/driver.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,8 @@ describe('Driver', () => {
625625
mode: 'WRITE',
626626
reactive: false,
627627
impersonatedUser: undefined,
628+
// @ts-expect-error
629+
log: driver?._log,
628630
...extra
629631
}
630632
}

packages/core/test/session.test.ts

Lines changed: 170 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@
1919
import { ConnectionProvider, Session, Connection, TransactionPromise, Transaction, BookmarkManager, bookmarkManager, NotificationFilter, int } from '../src'
2020
import { bookmarks } from '../src/internal'
2121
import { ACCESS_MODE_READ, FETCH_ALL } from '../src/internal/constants'
22+
import { Logger } from '../src/internal/logger'
2223
import ManagedTransaction from '../src/transaction-managed'
23-
import { AuthToken } from '../src/types'
24+
import { AuthToken, LoggerFunction } from '../src/types'
2425
import FakeConnection from './utils/connection.fake'
2526
import { validNotificationFilters } from './utils/notification-filters.fixtures'
2627
import fc from 'fast-check'
@@ -497,6 +498,56 @@ describe('session', () => {
497498
)
498499
)
499500
})
501+
502+
it('should log a warning for timeout configurations with sub milliseconds', async () => {
503+
return await fc.assert(
504+
fc.asyncProperty(
505+
fc
506+
.float({ min: 0, noNaN: true })
507+
.filter((timeout: number) => !Number.isInteger(timeout)),
508+
async (timeout: number) => {
509+
const connection = mockBeginWithSuccess(newFakeConnection())
510+
511+
const { session, loggerFunction } = setupSession({
512+
connection,
513+
beginTx: false,
514+
database: 'neo4j'
515+
})
516+
517+
await session.beginTransaction({ timeout })
518+
519+
expect(loggerFunction).toBeCalledWith(
520+
'info',
521+
`Transaction timeout expected to be an integer, got: ${timeout}. The value will be round up.`
522+
)
523+
}
524+
)
525+
)
526+
})
527+
528+
it('should not log a warning for timeout configurations without sub milliseconds', async () => {
529+
return await fc.assert(
530+
fc.asyncProperty(
531+
fc.nat(),
532+
async (timeout: number) => {
533+
const connection = mockBeginWithSuccess(newFakeConnection())
534+
535+
const { session, loggerFunction } = setupSession({
536+
connection,
537+
beginTx: false,
538+
database: 'neo4j'
539+
})
540+
541+
await session.beginTransaction({ timeout })
542+
543+
expect(loggerFunction).not.toBeCalledWith(
544+
'info',
545+
`Transaction timeout expected to be an integer, got: ${timeout}. The value will be round up.`
546+
)
547+
}
548+
)
549+
)
550+
})
500551
})
501552

502553
describe('.commit()', () => {
@@ -634,6 +685,68 @@ describe('session', () => {
634685
)
635686
)
636687
})
688+
689+
it('should log a warning for timeout configurations with sub milliseconds', async () => {
690+
return await fc.assert(
691+
fc.asyncProperty(
692+
fc
693+
.float({ min: 0, noNaN: true })
694+
.filter((timeout: number) => !Number.isInteger(timeout)),
695+
async (timeout: number) => {
696+
const connection = mockBeginWithSuccess(newFakeConnection())
697+
const { session, loggerFunction } = setupSession({
698+
connection,
699+
beginTx: false,
700+
fetchSize: FETCH_ALL
701+
})
702+
703+
// @ts-expect-error
704+
jest.spyOn(Transaction.prototype, 'run').mockImplementation(async () => await Promise.resolve())
705+
const query = 'RETURN $a'
706+
const params = { a: 1 }
707+
708+
await execute(session)(async (tx: ManagedTransaction) => {
709+
await tx.run(query, params)
710+
}, { timeout })
711+
712+
expect(loggerFunction).toBeCalledWith(
713+
'info',
714+
`Transaction timeout expected to be an integer, got: ${timeout}. The value will be round up.`
715+
)
716+
}
717+
)
718+
)
719+
})
720+
721+
it('should not log a warning for timeout configurations without sub milliseconds', async () => {
722+
return await fc.assert(
723+
fc.asyncProperty(
724+
fc.nat(),
725+
async (timeout: number) => {
726+
const connection = mockBeginWithSuccess(newFakeConnection())
727+
const { session, loggerFunction } = setupSession({
728+
connection,
729+
beginTx: false,
730+
fetchSize: FETCH_ALL
731+
})
732+
733+
// @ts-expect-error
734+
jest.spyOn(Transaction.prototype, 'run').mockImplementation(async () => await Promise.resolve())
735+
const query = 'RETURN $a'
736+
const params = { a: 1 }
737+
738+
await execute(session)(async (tx: ManagedTransaction) => {
739+
await tx.run(query, params)
740+
}, { timeout })
741+
742+
expect(loggerFunction).not.toBeCalledWith(
743+
'info',
744+
`Transaction timeout expected to be an integer, got: ${timeout}. The value will be round up.`
745+
)
746+
}
747+
)
748+
)
749+
})
637750
})
638751

639752
describe('.run()', () => {
@@ -986,6 +1099,56 @@ describe('session', () => {
9861099
)
9871100
)
9881101
})
1102+
1103+
it('should log a warning for timeout configurations with sub milliseconds', async () => {
1104+
return await fc.assert(
1105+
fc.asyncProperty(
1106+
fc
1107+
.float({ min: 0, noNaN: true })
1108+
.filter((timeout: number) => !Number.isInteger(timeout)),
1109+
async (timeout: number) => {
1110+
const connection = newFakeConnection()
1111+
1112+
const { session, loggerFunction } = setupSession({
1113+
connection,
1114+
beginTx: false,
1115+
database: 'neo4j'
1116+
})
1117+
1118+
await session.run('query', {}, { timeout })
1119+
1120+
expect(loggerFunction).toBeCalledWith(
1121+
'info',
1122+
`Transaction timeout expected to be an integer, got: ${timeout}. The value will be round up.`
1123+
)
1124+
}
1125+
)
1126+
)
1127+
})
1128+
1129+
it('should not log a warning for timeout configurations without sub milliseconds', async () => {
1130+
return await fc.assert(
1131+
fc.asyncProperty(
1132+
fc.nat(),
1133+
async (timeout: number) => {
1134+
const connection = newFakeConnection()
1135+
1136+
const { session, loggerFunction } = setupSession({
1137+
connection,
1138+
beginTx: false,
1139+
database: 'neo4j'
1140+
})
1141+
1142+
await session.run('query', {}, { timeout })
1143+
1144+
expect(loggerFunction).not.toBeCalledWith(
1145+
'info',
1146+
`Transaction timeout expected to be an integer, got: ${timeout}. The value will be round up.`
1147+
)
1148+
}
1149+
)
1150+
)
1151+
})
9891152
})
9901153
})
9911154

@@ -1049,8 +1212,10 @@ function setupSession ({
10491212
bookmarkManager?: BookmarkManager
10501213
notificationFilter?: NotificationFilter
10511214
auth?: AuthToken
1052-
}): { session: Session, connectionProvider: ConnectionProvider } {
1215+
}): { session: Session, connectionProvider: ConnectionProvider, loggerFunction: LoggerFunction } {
10531216
const connectionProvider = new ConnectionProvider()
1217+
const loggerFunction = jest.fn()
1218+
const log = new Logger('debug', loggerFunction)
10541219
connectionProvider.acquireConnection = jest.fn(async () => await Promise.resolve(connection))
10551220
connectionProvider.close = async () => await Promise.resolve()
10561221

@@ -1064,13 +1229,14 @@ function setupSession ({
10641229
bookmarks: lastBookmarks,
10651230
bookmarkManager,
10661231
notificationFilter,
1067-
auth
1232+
auth,
1233+
log
10681234
})
10691235

10701236
if (beginTx) {
10711237
session.beginTransaction().catch(e => { }) // force session to acquire new connection
10721238
}
1073-
return { session, connectionProvider }
1239+
return { session, connectionProvider, loggerFunction }
10741240
}
10751241

10761242
function newFakeConnection (): FakeConnection {

0 commit comments

Comments
 (0)