Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ jobs:
POSTGRES_HOST_AUTH_METHOD: 'trust'
POSTGRES_INITDB_ARGS: "--auth-local=md5"
GS_DB: ci_db_test
DB_TYPE: opengauss
ports:
- 5432:5432
# options: --health-cmd "su - omm -c \"gs_ctl status\"" --health-interval 10s --health-timeout 5s --health-retries 5
Expand All @@ -58,6 +59,7 @@ jobs:
GAUSSTESTNOSSL: 'true'
SHA256_TEST_GAUSSUSER: sha256_test
SHA256_TEST_GAUSSPASSWORD: test4@scram
DB_TYPE: opengauss
steps:
- name: Show OS
run: |
Expand Down
2 changes: 1 addition & 1 deletion packages/gaussdb-cursor/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ describe('cursor', function () {
})

it('read huge result', function (done) {
this.timeout(10000)
this.timeout(1000 * 30) // 提高超时时间到 30 秒
const text = 'SELECT generate_series as num FROM generate_series(0, 100000)'
const values = []
const cursor = this.gaussdbCursor(text, values)
Expand Down
10 changes: 9 additions & 1 deletion packages/gaussdb-node/lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -345,9 +345,17 @@ class Client extends EventEmitter {
return
}
this._connectionError = true
this._connecting = false
clearTimeout(this.connectionTimeoutHandle)

if (this.connection && this.connection.stream) {
this.connection.stream.destroy()
}

if (this._connectionCallback) {
return this._connectionCallback(err)
const callback = this._connectionCallback
this._connectionCallback = null
return callback(err)
}
this.emit('error', err)
}
Expand Down
11 changes: 10 additions & 1 deletion packages/gaussdb-node/test/integration/client/appname-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,18 @@ function getAppName(conf, cb) {
)
}

// Determine default application_name based on database type
// GaussDB defaults to 'dn_6002', OpenGauss defaults to empty string
const getDefaultAppName = () => {
// Check environment variable to determine database type
const dbType = process.env.DB_TYPE || process.env.GAUSS_TYPE || 'gaussdb'
return dbType.toLowerCase() === 'opengauss' ? '' : 'dn_6002'
}

suite.test('No default appliation_name ', function (done) {
const expectedAppName = getDefaultAppName()
getAppName({}, function (res) {
assert.strictEqual(res, '')
assert.strictEqual(res, expectedAppName)
done()
})
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ $$;
assert(notice instanceof Error === false)
assert.strictEqual(notice.name, 'notice')
assert.strictEqual(notice.message, 'hello, world!')
assert.strictEqual(notice.detail, 'this is a test')
assert.ok(notice.detail && notice.detail.includes('this is a test'), `Unexpected notice detail: ${notice.detail}`)
assert.strictEqual(notice.code, '23505')
done()
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,16 @@ const testForTypeCoercion = function (type) {
}
const expected = val + ' (' + typeof val + ')'
const returned = row.col + ' (' + typeof row.col + ')'
assert.strictEqual(row.col, val, 'expected ' + type.name + ' of ' + expected + ' but got ' + returned)
if (type.name === 'real') {
// GaussDB 使用 32 位浮点数表示 real 类型,允许有微小的误差 -101.300003 vs -101.3
const delta = Math.abs(row.col - val)
assert(
delta < 1e-5,
'expected ' + type.name + ' of ' + expected + ' but got ' + returned + ' (difference ' + delta + ')'
)
} else {
assert.strictEqual(row.col, val, 'expected ' + type.name + ' of ' + expected + ' but got ' + returned)
}
},
'row should have been called for ' + type.name + ' of ' + val
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ const assert = require('assert')

const suite = new helper.Suite()
suite.test('connecting to invalid port', (cb) => {
const pool = new gaussdb.Pool({ port: 13801 })
pool.connect().catch((e) => cb())
const pool = new gaussdb.Pool({ port: 13801, connectionTimeoutMillis: 2000 })
pool.connect().catch(() => {
pool.end()
cb()
})
})

suite.test('errors emitted on checked-out clients', (cb) => {
Expand All @@ -18,38 +21,19 @@ suite.test('errors emitted on checked-out clients', (cb) => {
client.query('SELECT NOW()', function () {
pool.connect(
assert.success(function (client2, done2) {
helper.versionGTE(
client2,
90200,
assert.success(function (isGreater) {
let killIdleQuery =
'SELECT pid, (SELECT pg_terminate_backend(pid)) AS killed FROM pg_stat_activity WHERE state = $1'
let params = ['idle']
if (!isGreater) {
killIdleQuery =
'SELECT procpid, (SELECT pg_terminate_backend(procpid)) AS killed FROM pg_stat_activity WHERE current_query LIKE $1'
params = ['%IDLE%']
}
client.once('error', (err) => {
client.on('error', (err) => {})
done(err)
cb()
})

client.once('error', (err) => {
client.on('error', (err) => {})
done(err)
cb()
})
// Simulate a network error by destroying the underlying socket
// pg_terminate_backend need superuser privilege
client.connection.stream.destroy(new Error('Simulated connection error'))

// kill the connection from client
client2.query(
killIdleQuery,
params,
assert.success(function (res) {
// check to make sure client connection actually was killed
// return client2 to the pool
done2()
pool.end()
})
)
})
)
// Return client2 to the pool
done2()
pool.end()
})
)
})
Expand All @@ -64,7 +48,16 @@ suite.test('connection-level errors cause queued queries to fail', (cb) => {
client.query(
'SELECT pg_terminate_backend(pg_backend_pid())',
assert.calls((err) => {
assert.equal(err.code, '57P01')
const dbType = process.env.DB_TYPE || process.env.GAUSS_TYPE || 'gaussdb'
if (dbType.toLowerCase() === 'opengauss') {
// In OpenGauss, pg_terminate_backend returns a proper DatabaseError
assert.equal(err.code, '57P01')
} else {
// Note: In GaussDB, pg_terminate_backend() drops the TCP connection immediately
// rather than returning a proper PostgreSQL DatabaseError with code '57P01'.
assert.equal(err.message, 'Connection terminated unexpectedly')
assert.equal(err.code, undefined)
}
})
)

Expand Down Expand Up @@ -96,7 +89,16 @@ suite.test('connection-level errors cause future queries to fail', (cb) => {
client.query(
'SELECT pg_terminate_backend(pg_backend_pid())',
assert.calls((err) => {
assert.equal(err.code, '57P01')
const dbType = process.env.DB_TYPE || process.env.GAUSS_TYPE || 'gaussdb'
if (dbType.toLowerCase() === 'opengauss') {
// In OpenGauss, pg_terminate_backend returns a proper DatabaseError
assert.equal(err.code, '57P01')
} else {
// Note: In GaussDB, pg_terminate_backend() drops the TCP connection immediately
// rather than returning a proper PostgreSQL DatabaseError with code '57P01'.
assert.equal(err.message, 'Connection terminated unexpectedly')
assert.equal(err.code, undefined)
}
})
)

Expand Down Expand Up @@ -132,5 +134,5 @@ suite.test('handles socket error during pool.query and destroys it immediately',
const stream = pool._clients[0].connection.stream
setTimeout(() => {
stream.emit('error', new Error('network issue'))
}, 100)
}, 1000)
})
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ pool.connect(function (err, client, done) {
done()

if (err) throw err
assert.equal(res.rows[0].body, '')
// Determine expected value based on database type
// GaussDB returns null for empty buffer, OpenGauss returns empty string
const dbType = process.env.DB_TYPE || process.env.GAUSS_TYPE || 'gaussdb'
const expectedValue = dbType.toLowerCase() === 'opengauss' ? '' : null
assert.equal(res.rows[0].body, expectedValue)
pool.end()
})
})
Expand Down
17 changes: 11 additions & 6 deletions packages/gaussdb-pool/test/bring-your-own-promise.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,33 @@ const checkType = (promise) => {
}

describe('Bring your own promise', function () {
this.timeout(10000) // 增加超时时间到10秒

it(
'uses supplied promise for operations',
co.wrap(function* () {
const pool = new Pool({ Promise: BluebirdPromise })
const client1 = yield checkType(pool.connect())
client1.release()
if (client1) client1.release()
yield checkType(pool.query('SELECT NOW()'))
const client2 = yield checkType(pool.connect())
// TODO - make sure pg supports BYOP as well
client2.release()
if (client2) client2.release()
yield checkType(pool.end())
})
)

it(
'uses promises in errors',
co.wrap(function* () {
const pool = new Pool({ Promise: BluebirdPromise, port: 48484 })
yield checkType(pool.connect())
yield checkType(pool.end())
const pool = new Pool({
Promise: BluebirdPromise,
port: 48484,
connectionTimeoutMillis: 1000,
max: 1,
})
yield checkType(pool.connect())
yield checkType(pool.query())
yield checkType(pool.query('SELECT NOW()'))
yield checkType(pool.end())
})
)
Expand Down
6 changes: 3 additions & 3 deletions packages/gaussdb-pool/test/connection-timeout.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ describe('connection timeout', () => {
)

it('should timeout on checkout of used connection', (done) => {
const pool = new Pool({ connectionTimeoutMillis: 100, max: 1 })
const pool = new Pool({ connectionTimeoutMillis: 1000, max: 1 })
pool.connect((err, client, release) => {
expect(err).to.be(undefined)
expect(client).to.not.be(undefined)
Expand Down Expand Up @@ -106,7 +106,7 @@ describe('connection timeout', () => {
})

it('should timeout on query if all clients are busy', (done) => {
const pool = new Pool({ connectionTimeoutMillis: 100, max: 1 })
const pool = new Pool({ connectionTimeoutMillis: 1000, max: 1 })
pool.connect((err, client, release) => {
expect(err).to.be(undefined)
expect(client).to.not.be(undefined)
Expand All @@ -120,7 +120,7 @@ describe('connection timeout', () => {
})

it('should recover from timeout errors', (done) => {
const pool = new Pool({ connectionTimeoutMillis: 100, max: 1 })
const pool = new Pool({ connectionTimeoutMillis: 1000, max: 1 })
pool.connect((err, client, release) => {
expect(err).to.be(undefined)
expect(client).to.not.be(undefined)
Expand Down
11 changes: 7 additions & 4 deletions packages/gaussdb-pool/test/error-handling.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,18 +196,19 @@ describe('pool error handling', function () {
it(
'continues to work and provide new clients',
co.wrap(function* () {
const pool = new Pool({ max: 1 })
const pool = new Pool({ connectionTimeoutMillis: 1000, max: 2 })
const errors = []
for (let i = 0; i < 20; i++) {
for (let i = 0; i < 10; i++) {
try {
yield pool.query('invalid sql')
} catch (err) {
errors.push(err)
}
}
expect(errors).to.have.length(20)
expect(errors).to.have.length(10)
expect(pool.idleCount).to.equal(0)
expect(pool.query).to.be.a(Function)
// 测试连接池是否还能正常工作
const res = yield pool.query('SELECT $1::text as name', ['brianc'])
expect(res.rows).to.have.length(1)
expect(res.rows[0].name).to.equal('brianc')
Expand Down Expand Up @@ -254,7 +255,9 @@ describe('pool error handling', function () {
})

setTimeout(() => {
pool._clients[0].end()
if (pool._clients && pool._clients[0]) {
pool._clients[0].end()
}
}, 1000)
})
})
28 changes: 20 additions & 8 deletions packages/gaussdb-pool/test/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,29 @@ describe('events', function () {
expect(client).to.be.ok()
acquireCount++
})
const promises = []
for (let i = 0; i < 10; i++) {
pool.connect(function (err, client, release) {
if (err) return done(err)
release()
// 为connect操作创建Promise
const connectPromise = new Promise((resolve, reject) => {
pool.connect(function (err, client, release) {
if (err) return reject(err)
release()
resolve()
})
})
pool.query('SELECT now()')
promises.push(connectPromise)
// 为query操作创建Promise
promises.push(pool.query('SELECT now()'))
}
setTimeout(function () {
expect(acquireCount).to.be(20)
pool.end(done)
}, 100)
Promise.all(promises)
.then(() => {
expect(acquireCount).to.be(20)
return pool.end()
})
.then(() => {
done()
})
.catch(done)
})

it('emits release every time a client is released', function (done) {
Expand Down
Loading