mirror of
https://github.com/bigchaindb/js-bigchaindb-driver.git
synced 2024-11-22 01:36:56 +01:00
add and fix tests
This commit is contained in:
parent
7d978286f5
commit
ad8a889ecc
@ -22,7 +22,6 @@
|
||||
"dev": "webpack -w",
|
||||
"clean": "rimraf dist/bundle dist/node",
|
||||
"test": "npm run lint && nyc ava test/ && npm run thanks && npm run report-coverage",
|
||||
"mine-test": "nyc ava test/connection/test_mine*",
|
||||
"thanks": "cowsay Hi, thanks for your interest in BigchainDB. We appreciate your contribution!",
|
||||
"release": "./node_modules/release-it/bin/release-it.js --src.tagName='v%s' --github.release --npm.publish --non-interactive",
|
||||
"release-minor": "./node_modules/release-it/bin/release-it.js minor --src.tagName='v%s' --github.release --npm.publish --non-interactive",
|
||||
|
@ -1,4 +1,4 @@
|
||||
import Transport from './Transport'
|
||||
import Transport from './transport'
|
||||
|
||||
const HEADER_BLACKLIST = ['content-type']
|
||||
const DEFAULT_NODE = 'http://localhost:9984'
|
||||
@ -44,7 +44,7 @@ export default class Connection {
|
||||
} else {
|
||||
// TODO normalize URL if needed
|
||||
const allHeaders = Object.assign({}, headers, node.headers)
|
||||
return { 'endpoint': node, 'headers': allHeaders }
|
||||
return { 'endpoint': node.endpoint, 'headers': allHeaders }
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,6 @@ export default class Connection {
|
||||
* @param operation
|
||||
*/
|
||||
listTransactions(assetId, operation) {
|
||||
console.log('listtransaction', assetId)
|
||||
return this._req(Connection.getApiUrls('transactions'), {
|
||||
query: {
|
||||
asset_id: assetId,
|
||||
|
@ -1,7 +1,6 @@
|
||||
export Ed25519Keypair from './Ed25519Keypair'
|
||||
|
||||
export Connection from './connection'
|
||||
export Request from './request'
|
||||
export Transaction from './transaction'
|
||||
export ccJsonLoad from './utils/ccJsonLoad'
|
||||
export ccJsonify from './utils/ccJsonify'
|
||||
|
@ -21,11 +21,11 @@ export default class Request {
|
||||
this.node = node
|
||||
this.requestConfig = requestConfig
|
||||
this.backoffTime = null
|
||||
this.retries = 0
|
||||
this.connectionError = null
|
||||
}
|
||||
|
||||
async request(endpoint, config, timeout) {
|
||||
// Num or retries to the same node
|
||||
this.retries = 0
|
||||
async request(endpoint, config, setTimeout) {
|
||||
// Load default fetch configuration and remove any falsy query parameters
|
||||
const requestConfig = Object.assign({}, this.node.headers, DEFAULT_REQUEST_CONFIG, config, {
|
||||
query: config.query && sanitize(config.query)
|
||||
@ -43,7 +43,7 @@ export default class Request {
|
||||
|
||||
// If `ConnectionError` occurs, a timestamp equal to now +
|
||||
// the default delay (`BACKOFF_DELAY`) is assigned to the object.
|
||||
// The timestamp is in UTC. Next time the function is called, it either
|
||||
// Next time the function is called, it either
|
||||
// waits till the timestamp is passed or raises `TimeoutError`.
|
||||
// If `ConnectionError` occurs two or more times in a row,
|
||||
// the retry count is incremented and the new timestamp is calculated
|
||||
@ -52,28 +52,27 @@ export default class Request {
|
||||
// If a request is successful, the backoff timestamp is removed,
|
||||
// the retry count is back to zero.
|
||||
|
||||
this.backoffTimedelta = this.getBackoffTimedelta()
|
||||
const backoffTimedelta = this.getBackoffTimedelta()
|
||||
|
||||
if (timeout != null && timeout < this.backoffTimedelta) {
|
||||
throw new Error()
|
||||
if (setTimeout != null && setTimeout < this.backoffTimedelta) {
|
||||
const errorObject = {
|
||||
message: 'TimeoutError'
|
||||
}
|
||||
throw errorObject
|
||||
}
|
||||
if (this.backoffTimedelta > 0) {
|
||||
await Request.sleep(this.backoffTimedelta)
|
||||
if (backoffTimedelta > 0) {
|
||||
await Request.sleep(backoffTimedelta)
|
||||
}
|
||||
this.timeout = this.timeout ? this.timeout - this.backoffTimedelta : timeout
|
||||
|
||||
this.timeout = setTimeout ? setTimeout - backoffTimedelta : setTimeout
|
||||
return baseRequest(apiUrl, requestConfig)
|
||||
.then(res => async function handleResponse() {
|
||||
res.json()
|
||||
if (!(res.status >= 200 && res.status < 300)) {
|
||||
console.log('Valid response')
|
||||
}
|
||||
})
|
||||
.then(res => res.json())
|
||||
.catch(err => {
|
||||
throw err
|
||||
// ConnectionError
|
||||
this.connectionError = err
|
||||
// throw err
|
||||
})
|
||||
.finally((res) => {
|
||||
this.updateBackoffTime(res)
|
||||
.finally(() => {
|
||||
this.updateBackoffTime()
|
||||
})
|
||||
}
|
||||
|
||||
@ -84,13 +83,13 @@ export default class Request {
|
||||
return (this.backoffTime - Date.now())
|
||||
}
|
||||
|
||||
updateBackoffTime(success) {
|
||||
if (success) {
|
||||
updateBackoffTime() {
|
||||
if (!this.connectionError) {
|
||||
this.retries = 0
|
||||
this.backoffTime = null
|
||||
} else {
|
||||
this.backoffTimedelta = BACKOFF_DELAY * (2 ** this.retries)
|
||||
this.backoffTime = Date.now() + this.backoffTimedelta
|
||||
const backoffTimedelta = BACKOFF_DELAY * (2 ** this.retries)
|
||||
this.backoffTime = Date.now() + backoffTimedelta
|
||||
this.retries += 1
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import Request from './request'
|
||||
|
||||
|
||||
@ -15,11 +19,8 @@ export default class Transport {
|
||||
if (this.connectionPool.length === 1) {
|
||||
return this.connectionPool[0]
|
||||
}
|
||||
return this.minBackoff()
|
||||
}
|
||||
|
||||
minBackoff() {
|
||||
let connection = this.connectionPool[0]
|
||||
|
||||
this.connectionPool.forEach(conn => {
|
||||
// 0 the lowest value is the time for Thu Jan 01 1970 01:00:00 GMT+0100 (CET)
|
||||
conn.backoffTime = conn.backoffTime ? conn.backoffTime : 0
|
||||
@ -29,28 +30,36 @@ export default class Transport {
|
||||
}
|
||||
|
||||
async forwardRequest(path, headers) {
|
||||
let response
|
||||
let connection
|
||||
while (!this.timeout || this.timeout > 0) {
|
||||
const connection = this.pickConnection()
|
||||
|
||||
connection = this.pickConnection()
|
||||
// Date in milliseconds
|
||||
const startTime = Date.now()
|
||||
try {
|
||||
// TODO wait until request is done
|
||||
const response = connection.request(
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
response = await connection.request(
|
||||
path,
|
||||
headers,
|
||||
this.timeout
|
||||
)
|
||||
return response
|
||||
const elapsed = Date.now() - startTime
|
||||
if (connection.backoffTime) {
|
||||
this.timeout += elapsed
|
||||
} else {
|
||||
return response
|
||||
}
|
||||
|
||||
if (connection.retries > 3) {
|
||||
throw connection.connectionError
|
||||
}
|
||||
} catch (err) {
|
||||
throw err
|
||||
} finally {
|
||||
const elapsed = Date.now() - startTime
|
||||
if (this.timeout) {
|
||||
this.timeout -= elapsed
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
const errorObject = {
|
||||
message: 'Timeout error',
|
||||
}
|
||||
throw errorObject
|
||||
}
|
||||
}
|
@ -1,8 +1,12 @@
|
||||
import test from 'ava'
|
||||
import sinon from 'sinon'
|
||||
|
||||
import { Connection, Request } from '../../src'
|
||||
import { API_PATH } from '../constants'
|
||||
import {
|
||||
Connection
|
||||
} from '../../src'
|
||||
import {
|
||||
API_PATH
|
||||
} from '../constants'
|
||||
|
||||
const conn = new Connection(API_PATH)
|
||||
|
||||
@ -37,22 +41,59 @@ test('Generate API URLS', t => {
|
||||
})
|
||||
})
|
||||
|
||||
// TODO Redefine test
|
||||
test('Request with custom headers', t => {
|
||||
const testConn = new Connection(API_PATH, { hello: 'world' })
|
||||
const expectedOptions = {
|
||||
test('Normalize node from an object', t => {
|
||||
const headers = {
|
||||
custom: 'headers'
|
||||
}
|
||||
const node = {
|
||||
endpoint: API_PATH,
|
||||
headers: {
|
||||
hello: 'world'
|
||||
}
|
||||
}
|
||||
const expectedNode = {
|
||||
'endpoint': API_PATH,
|
||||
'headers': {
|
||||
hello: 'world',
|
||||
custom: 'headers'
|
||||
}
|
||||
}
|
||||
|
||||
// request is read only, cannot be mocked?
|
||||
sinon.spy(Request, 'default')
|
||||
testConn._req(API_PATH, { headers: { custom: 'headers' } })
|
||||
t.deepEqual(Connection.normalizeNode(node, headers), expectedNode)
|
||||
})
|
||||
|
||||
t.truthy(Request.default.calledWith(API_PATH, expectedOptions))
|
||||
Request.default.restore()
|
||||
test('Normalize node from a string', t => {
|
||||
const headers = {
|
||||
custom: 'headers'
|
||||
}
|
||||
const expectedNode = {
|
||||
'endpoint': API_PATH,
|
||||
'headers': {
|
||||
custom: 'headers'
|
||||
}
|
||||
}
|
||||
|
||||
t.deepEqual(Connection.normalizeNode(API_PATH, headers), expectedNode)
|
||||
})
|
||||
|
||||
test('Request with custom headers', t => {
|
||||
const testConn = new Connection(API_PATH, {
|
||||
hello: 'world'
|
||||
})
|
||||
const expectedOptions = {
|
||||
headers: {
|
||||
custom: 'headers'
|
||||
}
|
||||
}
|
||||
const PATH = 'blocks'
|
||||
testConn.transport.forwardRequest = sinon.spy()
|
||||
|
||||
testConn._req(PATH, {
|
||||
headers: {
|
||||
custom: 'headers'
|
||||
}
|
||||
})
|
||||
t.truthy(testConn.transport.forwardRequest.calledWith(PATH, expectedOptions))
|
||||
})
|
||||
|
||||
|
||||
|
@ -36,7 +36,9 @@ test('Valid CREATE transaction', t => {
|
||||
const txSigned = Transaction.signTransaction(tx, alice.privateKey)
|
||||
|
||||
return conn.postTransaction(txSigned)
|
||||
.then(resTx => t.truthy(resTx))
|
||||
.then(resTx => {
|
||||
t.truthy(resTx)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
35
test/transport/test_transport.js
Normal file
35
test/transport/test_transport.js
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import test from 'ava'
|
||||
|
||||
import {
|
||||
Connection
|
||||
} from '../../src'
|
||||
|
||||
|
||||
test('Pick connection with earliest backoff time', t => {
|
||||
const path1 = 'http://localhost:9984/api/v1/'
|
||||
const path2 = 'http://localhost:9984/api/wrong/'
|
||||
|
||||
const conn = new Connection([path1, path2])
|
||||
|
||||
conn.searchAssets('example')
|
||||
const connection1 = conn.transport.connectionPool[0]
|
||||
|
||||
t.deepEqual(conn.transport.pickConnection(), connection1)
|
||||
})
|
||||
|
||||
test('Pick connection with earliest backoff time', async t => {
|
||||
const path1 = 'http://localhost:9984/api/v1/'
|
||||
const path2 = 'http://localhost:9984/api/wrong/'
|
||||
|
||||
// Reverse order
|
||||
const conn = new Connection([path2, path1])
|
||||
await conn.searchAssets('example')
|
||||
|
||||
const connection1 = conn.transport.connectionPool[1]
|
||||
|
||||
t.deepEqual(conn.transport.pickConnection(), connection1)
|
||||
})
|
Loading…
Reference in New Issue
Block a user