add and fix tests

This commit is contained in:
manolodewiner 2018-08-23 17:14:59 +02:00
parent 7d978286f5
commit ad8a889ecc
8 changed files with 139 additions and 56 deletions

View File

@ -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",

View File

@ -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,

View File

@ -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'

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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))
})

View File

@ -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)
})
})

View 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)
})