From c8e4b28523f1aee7d4dd114f6ef878b02b377293 Mon Sep 17 00:00:00 2001 From: Stephen Hess Date: Fri, 5 May 2017 12:35:33 -0400 Subject: [PATCH] initial commit --- .gitignore | 33 ++ .jshintignore | 1 + .jshintrc | 22 ++ ServiceConfiguration.js | 48 +++ http_json.js | 107 +++++++ package.json | 35 +++ test/ServiceConfiguration.js | 47 +++ test/http_json.js | 571 +++++++++++++++++++++++++++++++++++ test/test.js | 2 + 9 files changed, 866 insertions(+) create mode 100644 .gitignore create mode 100644 .jshintignore create mode 100644 .jshintrc create mode 100644 ServiceConfiguration.js create mode 100644 http_json.js create mode 100644 package.json create mode 100644 test/ServiceConfiguration.js create mode 100644 test/http_json.js create mode 100644 test/test.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e920c16 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +node_modules + +# Optional npm cache directory +.npm + +# Optional REPL history +.node_repl_history diff --git a/.jshintignore b/.jshintignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.jshintignore @@ -0,0 +1 @@ +node_modules diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..e5c5749 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,22 @@ +{ + "node": true, + "curly": true, + "eqeqeq": true, + "esversion": 6, + "freeze": true, + "immed": true, + "indent": 2, + "latedef": false, + "newcap": true, + "noarg": true, + "noempty": true, + "nonbsp": true, + "nonew": true, + "plusplus": false, + "quotmark": "single", + "undef": true, + "unused": false, + "maxparams": 4, + "maxdepth": 4, + "maxlen": 140 +} diff --git a/ServiceConfiguration.js b/ServiceConfiguration.js new file mode 100644 index 0000000..3fe0d75 --- /dev/null +++ b/ServiceConfiguration.js @@ -0,0 +1,48 @@ +'use strict'; + +const _ = require('lodash'); + +class ServiceConfiguration { + constructor(name, config) { + if (_.isEmpty(name)) { + throw 'name is required'; + } + + this.name = name; + this.baseUrl = config.url; + this.timeout = config.timeout || 250; + this.retries = config.retries || 3; + + } + + getName() { + return this.name; + } + + getBaseUrl() { + return this.baseUrl; + } + + getUrl() { + return this.baseUrl; + } + + getRetries() { + return this.retries; + } + + getTimeout() { + return this.timeout; + } + + getParameters() { + return {}; + } + + getHeaders() { + return {}; + } + +} + +module.exports = ServiceConfiguration; diff --git a/http_json.js b/http_json.js new file mode 100644 index 0000000..f004dd7 --- /dev/null +++ b/http_json.js @@ -0,0 +1,107 @@ +const request = require('superagent'); +const _ = require('lodash'); + +const ServiceConfiguration = require('./ServiceConfiguration'); + +function isDoNotTrack(headers) { + return _.has(headers, 'DNT') || + _.has(headers, 'dnt') || + _.has(headers, 'do_not_track'); +} + +// superagent doesn't exposed the assembled GET request, so synthesize it +function synthesizeUrl(serviceConfig, req) { + const parameters = _.map(serviceConfig.getParameters(), (value, key) => { + return `${key}=${value}`; + }).join('&'); + + if (parameters) { + return encodeURI(`${serviceConfig.getUrl(req)}?${parameters}`); + } else { + return serviceConfig.getUrl(req); + } + +} + +module.exports = function setup(serviceConfig) { + if (!(serviceConfig instanceof ServiceConfiguration)) { + throw Error('serviceConfig should be an instance of ServiceConfiguration'); + } + + const logger = require( 'pelias-logger' ).get( serviceConfig.getName() ); + + if (_.isEmpty(serviceConfig.getBaseUrl())) { + logger.warn(`${serviceConfig.getName()} service disabled`); + + return (req, callback) => { + // respond with an error to any call + callback(`${serviceConfig.getName()} service disabled`); + }; + + } + + logger.info(`using ${serviceConfig.getName()} service at ${serviceConfig.getBaseUrl()}`); + return (req, callback) => { + const headers = serviceConfig.getHeaders(req) || {}; + + // save off do_not_track value for later check + const do_not_track = isDoNotTrack(req.headers); + + if (do_not_track) { + headers.dnt = '1'; + } + + request + .get(serviceConfig.getUrl(req)) + .set(headers) + .timeout(serviceConfig.getTimeout()) + .retry(serviceConfig.getRetries()) + .accept('json') + .query(serviceConfig.getParameters(req)) + .on('error', (err) => { + if (err.status) { + // first handle case where a non-200 was returned + if (do_not_track) { + logger.error(`${serviceConfig.getBaseUrl()} [do_not_track] returned status ${err.status}: ${err.response.text}`); + return callback(`${serviceConfig.getBaseUrl()} [do_not_track] returned status ${err.status}: ${err.response.text}`); + } else { + logger.error(`${synthesizeUrl(serviceConfig, req)} returned status ${err.status}: ${err.response.text}`); + return callback(`${synthesizeUrl(serviceConfig, req)} returned status ${err.status}: ${err.response.text}`); + } + + } + + // handle case that something catastrophic happened while contacting the server + if (do_not_track) { + logger.error(`${serviceConfig.getBaseUrl()} [do_not_track]: ${JSON.stringify(err)}`); + return callback(err); + } else { + logger.error(`${serviceConfig.getUrl(req)}: ${JSON.stringify(err)}`); + return callback(err); + } + + }) + .end((err, response) => { + // bail early if there's an error (shouldn't happen since it was already handled above) + if (err) { + return; + } + + // if json was returned then just return it + if (response.type === 'application/json') { + return callback(null, response.body); + } + + if (do_not_track) { + logger.error(`${serviceConfig.getBaseUrl()} [do_not_track] could not parse response: ${response.text}`); + return callback(`${serviceConfig.getBaseUrl()} [do_not_track] could not parse response: ${response.text}`); + } else { + logger.error(`${synthesizeUrl(serviceConfig, req)} could not parse response: ${response.text}`); + return callback(`${synthesizeUrl(serviceConfig, req)} could not parse response: ${response.text}`); + } + + }); + + }; + +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..87d2b67 --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "pelias-microservice-wrapper", + "version": "1.0.0", + "description": "Module that wraps ", + "main": "index.js", + "scripts": { + "test": "node test/test | tap-dot", + "lint": "jshint .", + "travis": "npm run check-dependencies && npm test", + "semantic-release": "semantic-release pre && npm publish && semantic-release post", + "validate": "npm ls", + "check-dependencies": "node_modules/.bin/npm-check --production" + }, + "author": "Mapzen", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/pelias/microservice-wrapper.git" + }, + "keywords": [ + "pelias" + ], + "devDependencies": { + "express": "^4.15.2", + "pelias-mock-logger": "^1.1.0", + "proxyquire": "^1.7.11", + "tape": "^4.6.3" + }, + "dependencies": { + "lodash": "^4.17.4", + "pelias-logger": "^0.2.0", + "superagent": "^3.5.2", + "tap-dot": "^1.0.5" + } +} diff --git a/test/ServiceConfiguration.js b/test/ServiceConfiguration.js new file mode 100644 index 0000000..0011c8a --- /dev/null +++ b/test/ServiceConfiguration.js @@ -0,0 +1,47 @@ +const tape = require('tape'); +const ServiceConfiguration = require('../ServiceConfiguration'); + +tape('ServiceConfiguration tests', (test) => { + test.test('timeout and retries overrides should be returned by getters', (t) => { + const configBlob = { + url: 'base url', + timeout: 17, + retries: 19 + }; + + const serviceConfiguration = new ServiceConfiguration('service name', configBlob); + + t.equals(serviceConfiguration.getName(), 'service name'); + t.equals(serviceConfiguration.getBaseUrl(), 'base url'); + t.deepEquals(serviceConfiguration.getParameters(), {}); + t.deepEquals(serviceConfiguration.getHeaders(), {}); + t.equals(serviceConfiguration.getUrl(), 'base url'); + t.equals(serviceConfiguration.getRetries(), 19); + t.equals(serviceConfiguration.getTimeout(), 17); + t.end(); + + }); + + test.test('configBlob w/o timeout or retries should default to 250 and 3, respectively', (t) => { + const configBlob = { + url: 'base url' + }; + + const serviceConfiguration = new ServiceConfiguration('service name', configBlob); + + t.equals(serviceConfiguration.getTimeout(), 250, 'should be a default of 250'); + t.equals(serviceConfiguration.getRetries(), 3, 'should be a default of 3'); + t.end(); + + }); + + test.test('missing name should throw error', (t) => { + t.throws(() => { + // lint complains if using `new` and not assigning to something + const config = new ServiceConfiguration(undefined, { url: 'base url' }); + }, /^name is required$/); + t.end(); + + }); + +}); diff --git a/test/http_json.js b/test/http_json.js new file mode 100644 index 0000000..5cd6957 --- /dev/null +++ b/test/http_json.js @@ -0,0 +1,571 @@ +'use strict'; + +const proxyquire = require('proxyquire').noCallThru(); +const express = require('express'); +const tape = require('tape'); + +const ServiceConfiguration = require('../ServiceConfiguration'); + +tape('service tests', (test) => { + test.test('valid interface', (t) => { + const logger = require('pelias-mock-logger')(); + + const service = proxyquire('../http_json', { + 'pelias-logger': logger + }); + + t.equal(typeof service, 'function', 'service is a function'); + t.end(); + }); + +}); + +tape('conforms_to tests', (test) => { + test.test('non-ServiceConfiguration instance should throw error', (t) => { + const serviceConfig = 'not an instance of serviceConfiguration'; + const http_json = require('../http_json'); + + t.throws(http_json.bind(null, serviceConfig), /serviceConfig should be an instance of ServiceConfiguration/); + t.end(); + + }); + +}); + +tape('do-nothing service tests', (test) => { + test.test('undefined config.url should return service that logs that config.name service is not available', (t) => { + const logger = require('pelias-mock-logger')(); + + const MockServiceConfig = class extends ServiceConfiguration { + constructor(o) { + super('foo', { } ); + } + }; + + const service = proxyquire('../http_json', { + 'pelias-logger': logger + })(new MockServiceConfig()); + + t.ok(logger.isWarnMessage(/^foo service disabled$/)); + + service({}, (err) => { + t.equals(err, 'foo service disabled'); + t.end(); + }); + + }); + +}); + +tape('failure conditions tests', (test) => { + test.test('server returning error should log it and return no results', (t) => { + const server = express().listen(); + const port = server.address().port; + + // immediately close the server so to ensure an error response + server.close(); + + const logger = require('pelias-mock-logger')(); + + const MockServiceConfig = class extends ServiceConfiguration { + constructor(o) { + super('foo', { url: `http://localhost:${port}` } ); + } + getUrl(req) { + return `http://localhost:${port}/built_url`; + } + }; + + const service = proxyquire('../http_json', { + 'pelias-logger': logger + })(new MockServiceConfig()); + + t.ok(logger.isInfoMessage(new RegExp(`using foo service at http://localhost:${port}`))); + + service({}, (err, results) => { + t.equals(err.code, 'ECONNREFUSED'); + t.notOk(results); + t.ok(logger.isErrorMessage(new RegExp(`^http://localhost:${port}/built_url: .*ECONNREFUSED`)), + 'there should be a connection refused error message'); + t.end(); + + server.close(); + + }); + + }); + + test.test('[DNT] server returning error should log it w/sanitized URL and return no results', (t) => { + const server = express().listen(); + const port = server.address().port; + + // immediately close the server so to ensure an error response + server.close(); + + const logger = require('pelias-mock-logger')(); + + const MockServiceConfig = class extends ServiceConfiguration { + constructor(o) { + super('foo', { url: `http://localhost:${port}` } ); + } + getUrl(req) { + return `http://localhost:${port}/built_url`; + } + }; + + const service = proxyquire('../http_json', { + 'pelias-logger': logger + })(new MockServiceConfig()); + + t.ok(logger.isInfoMessage(new RegExp(`using foo service at http://localhost:${port}`))); + + const req = { + headers: { + dnt: 1 + } + }; + + service(req, (err, results) => { + t.equals(err.code, 'ECONNREFUSED'); + t.notOk(results); + t.ok(logger.isErrorMessage(new RegExp(`^http://localhost:${port} \\[do_not_track\\]: .*ECONNREFUSED`)), + 'there should be a connection refused error message'); + t.end(); + + server.close(); + + }); + + }); + + test.test('server returning non-200 response should log error and return no results', (t) => { + const webServer = express(); + webServer.get('/some_endpoint', (req, res, next) => { + t.notOk(req.headers.hasOwnProperty('dnt'), 'dnt header should not have been passed'); + + t.equals(req.headers.header1, 'header1 value', 'all headers should have been passed'); + t.deepEquals(req.query, { param1: 'param1 value', param2: 'param2 value' }); + + res.status(400).send('a bad request was made'); + }); + + const server = webServer.listen(); + const port = server.address().port; + + const logger = require('pelias-mock-logger')(); + + const MockServiceConfig = class extends ServiceConfiguration { + constructor(o) { + super('foo', { url: `http://localhost:${port}` } ); + } + getUrl(req) { + return `http://localhost:${port}/some_endpoint`; + } + getParameters(req) { + return { param1: 'param1 value', param2: 'param2 value' }; + } + getHeaders(req) { + return { header1: 'header1 value' }; + } + }; + + const service = proxyquire('../http_json', { + 'pelias-logger': logger + })(new MockServiceConfig()); + + t.ok(logger.isInfoMessage(new RegExp(`using foo service at http://localhost:${port}`))); + + service({}, (err, results) => { + t.equals(err, `http://localhost:${port}/some_endpoint?param1=param1%20value¶m2=param2%20value ` + + 'returned status 400: a bad request was made'); + t.notOk(results); + t.ok(logger.isErrorMessage(`http://localhost:${port}/some_endpoint?param1=param1%20value¶m2=param2%20value ` + + `returned status 400: a bad request was made`)); + t.end(); + + server.close(); + + }); + + }); + + test.test('[DNT] server returning non-200 response should log sanitized error and return no results', (t) => { + const webServer = express(); + webServer.get('/some_endpoint', (req, res, next) => { + t.equals(req.headers.dnt, '1'); + + t.equals(req.headers.header1, 'header1 value', 'all headers should have been passed'); + t.deepEquals(req.query, { param1: 'param1 value', param2: 'param2 value' }); + + res.status(400).send('a bad request was made'); + }); + + const server = webServer.listen(); + const port = server.address().port; + + const logger = require('pelias-mock-logger')(); + + const MockServiceConfig = class extends ServiceConfiguration { + constructor(o) { + super('foo', { url: `http://localhost:${port}` } ); + } + getUrl(req) { + return `http://localhost:${port}/some_endpoint`; + } + getParameters(req) { + return { param1: 'param1 value', param2: 'param2 value' }; + } + getHeaders(req) { + return { header1: 'header1 value' }; + } + }; + + const service = proxyquire('../http_json', { + 'pelias-logger': logger + })(new MockServiceConfig()); + + t.ok(logger.isInfoMessage(new RegExp(`using foo service at http://localhost:${port}`))); + + const req = { + headers: { + dnt: 1 + } + }; + + service(req, (err, results) => { + t.equals(err, `http://localhost:${port} [do_not_track] returned status 400: a bad request was made`); + t.notOk(results); + t.ok(logger.isErrorMessage(`http://localhost:${port} [do_not_track] ` + + `returned status 400: a bad request was made`)); + t.end(); + + server.close(); + + }); + + }); + + test.test('server returning 200 statusCode but with non-JSON response should log error and return undefined', (t) => { + const webServer = express(); + webServer.get('/some_endpoint', (req, res, next) => { + t.notOk(req.headers.hasOwnProperty('dnt'), 'dnt header should not have been passed'); + + t.equals(req.headers.header1, 'header1 value', 'all headers should have been passed'); + t.deepEquals(req.query, { param1: 'param1 value', param2: 'param2 value' }); + + res.set('Content-Type', 'text/plain').status(200).send('this is not parseable as JSON'); + }); + + const server = webServer.listen(); + const port = server.address().port; + + const logger = require('pelias-mock-logger')(); + + const MockServiceConfig = class extends ServiceConfiguration { + constructor(o) { + super('foo', { url: `http://localhost:${port}` } ); + } + getUrl(req) { + return `http://localhost:${port}/some_endpoint`; + } + getParameters(req) { + return { param1: 'param1 value', param2: 'param2 value' }; + } + getHeaders(req) { + return { header1: 'header1 value' }; + } + }; + + const service = proxyquire('../http_json', { + 'pelias-logger': logger + })(new MockServiceConfig()); + + t.ok(logger.isInfoMessage(new RegExp(`using foo service at http://localhost:${port}`))); + + service({}, (err, results) => { + t.equals(err, `http://localhost:${port}/some_endpoint?param1=param1%20value¶m2=param2%20value ` + + `could not parse response: this is not parseable as JSON`); + t.notOk(results, 'should return undefined'); + t.ok(logger.isErrorMessage(`http://localhost:${port}/some_endpoint?param1=param1%20value¶m2=param2%20value ` + + `could not parse response: this is not parseable as JSON`)); + t.end(); + + server.close(); + + }); + + }); + + test.test('[DNT] server returning 200 statusCode but with non-JSON response should log sanitized error and return undefined', (t) => { + const webServer = express(); + webServer.get('/some_endpoint', (req, res, next) => { + t.equals(req.headers.dnt, '1'); + + t.equals(req.headers.header1, 'header1 value', 'all headers should have been passed'); + t.deepEquals(req.query, { param1: 'param1 value', param2: 'param2 value' }); + + res.status(200).send('this is not parseable as JSON'); + }); + + const server = webServer.listen(); + const port = server.address().port; + + const logger = require('pelias-mock-logger')(); + + const MockServiceConfig = class extends ServiceConfiguration { + constructor(o) { + super('foo', { url: `http://localhost:${port}` } ); + } + getUrl(req) { + return `http://localhost:${port}/some_endpoint`; + } + getParameters(req) { + return { param1: 'param1 value', param2: 'param2 value' }; + } + getHeaders(req) { + return { header1: 'header1 value' }; + } + }; + + const service = proxyquire('../http_json', { + 'pelias-logger': logger + })(new MockServiceConfig()); + + t.ok(logger.isInfoMessage(new RegExp(`using foo service at http://localhost:${port}`))); + + const req = { + headers: { + dnt: 1 + } + }; + + service(req, (err, results) => { + t.equals(err, `http://localhost:${port} [do_not_track] ` + + `could not parse response: this is not parseable as JSON`); + t.notOk(results, 'should return undefined'); + t.ok(logger.isErrorMessage(`http://localhost:${port} [do_not_track] ` + + `could not parse response: this is not parseable as JSON`)); + t.end(); + + server.close(); + + }); + + }); + + test.test('server timing out on all requests should log and return error', (t) => { + const webServer = express(); + let requestCount = 0; + webServer.get('/some_endpoint', (req, res, next) => { + requestCount++; + res.set('Content-Type', 'text/plain').status(503).send('request timeout'); + }); + + const server = webServer.listen(); + const port = server.address().port; + + const logger = require('pelias-mock-logger')(); + + const MockServiceConfig = class extends ServiceConfiguration { + constructor(o) { + super('foo', { url: `http://localhost:${port}` } ); + } + getUrl(req) { + return `http://localhost:${port}/some_endpoint`; + } + getParameters(req) { + return { param1: 'param1 value', param2: 'param2 value' }; + } + getHeaders(req) { + return { header1: 'header1 value' }; + } + getRetries() { + return 1; + } + }; + + const service = proxyquire('../http_json', { + 'pelias-logger': logger + })(new MockServiceConfig()); + + t.ok(logger.isInfoMessage(new RegExp(`using foo service at http://localhost:${port}`))); + + service({}, (err, results) => { + t.equals(err, `http://localhost:${port}/some_endpoint?param1=param1%20value¶m2=param2%20value ` + + 'returned status 503: request timeout'); + t.notOk(results); + t.ok(logger.isErrorMessage(`http://localhost:${port}/some_endpoint?param1=param1%20value¶m2=param2%20value ` + + `returned status 503: request timeout`)); + t.equals(requestCount, 2); + t.end(); + + server.close(); + + }); + + }); + +}); + +tape('success conditions tests', (test) => { + test.test('server returning statusCode 200 should return no error and parsed output', (t) => { + const webServer = express(); + webServer.get('/some_endpoint', (req, res, next) => { + t.notOk(req.headers.hasOwnProperty('dnt'), 'dnt header should not have been passed'); + + t.equals(req.headers.header1, 'header1 value', 'all headers should have been passed'); + t.deepEquals(req.query, { param1: 'param1 value', param2: 'param2 value' }); + + res.status(200).json([1, 2, 3]); + }); + + const server = webServer.listen(); + const port = server.address().port; + + const logger = require('pelias-mock-logger')(); + + const MockServiceConfig = class extends ServiceConfiguration { + constructor(o) { + super('foo', { url: `http://localhost:${port}` } ); + } + getUrl(req) { + return `http://localhost:${port}/some_endpoint`; + } + getParameters(req) { + return { param1: 'param1 value', param2: 'param2 value' }; + } + getHeaders(req) { + return { header1: 'header1 value' }; + } + }; + + const service = proxyquire('../http_json', { + 'pelias-logger': logger + })(new MockServiceConfig()); + + t.ok(logger.isInfoMessage(new RegExp(`using foo service at http://localhost:${port}`))); + + service({}, (err, results) => { + t.notOk(err, 'should be no error'); + t.deepEquals(results, [1, 2, 3]); + t.notOk(logger.hasErrorMessages()); + t.end(); + + server.close(); + + }); + + }); + + test.test('getHeaders returning undefined should use empty headers object', (t) => { + const webServer = express(); + webServer.get('/some_endpoint', (req, res, next) => { + t.equals(req.headers.dnt, '1'); + + t.deepEquals(req.query, { param1: 'param1 value', param2: 'param2 value' }); + + res.status(200).json([1, 2, 3]); + }); + + const server = webServer.listen(); + const port = server.address().port; + + const logger = require('pelias-mock-logger')(); + + const MockServiceConfig = class extends ServiceConfiguration { + constructor(o) { + super('foo', { url: `http://localhost:${port}` } ); + } + getUrl(req) { + return `http://localhost:${port}/some_endpoint`; + } + getParameters(req) { + return { param1: 'param1 value', param2: 'param2 value' }; + } + getHeaders(req) { + return undefined; + } + }; + + const service = proxyquire('../http_json', { + 'pelias-logger': logger + })(new MockServiceConfig()); + + t.ok(logger.isInfoMessage(new RegExp(`using foo service at http://localhost:${port}`))); + + const req = { + headers: { + dnt: 1 + } + }; + + service(req, (err, results) => { + t.notOk(err, 'should be no error'); + t.deepEquals(results, [1, 2, 3]); + t.notOk(logger.hasErrorMessages()); + t.end(); + + server.close(); + + }); + + }); + + test.test('server succeeding on last timeout chance should return no error and parsed output', (t) => { + const webServer = express(); + let requestCount = 0; + webServer.get('/some_endpoint', (req, res, next) => { + if (++requestCount < 3) { + res.status(503); + + } else { + t.notOk(req.headers.hasOwnProperty('dnt'), 'dnt header should not have been passed'); + t.equals(req.headers.header1, 'header1 value', 'all headers should have been passed'); + t.deepEquals(req.query, { param1: 'param1 value', param2: 'param2 value' }); + + res.status(200).json([1, 2, 3]); + + } + + }); + + const server = webServer.listen(); + const port = server.address().port; + + const logger = require('pelias-mock-logger')(); + + const MockServiceConfig = class extends ServiceConfiguration { + constructor(o) { + super('foo', { url: `http://localhost:${port}` } ); + } + getUrl(req) { + return `http://localhost:${port}/some_endpoint`; + } + getParameters(req) { + return { param1: 'param1 value', param2: 'param2 value' }; + } + getHeaders(req) { + return { header1: 'header1 value' }; + } + }; + + const service = proxyquire('../http_json', { + 'pelias-logger': logger + })(new MockServiceConfig()); + + t.ok(logger.isInfoMessage(new RegExp(`using foo service at http://localhost:${port}`))); + + service({}, (err, results) => { + t.notOk(err, 'should be no error'); + t.deepEquals(results, [1, 2, 3]); + t.notOk(logger.hasErrorMessages()); + t.equals(requestCount, 3); + t.end(); + + server.close(); + + }); + + }); + +}); diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..fc00f6a --- /dev/null +++ b/test/test.js @@ -0,0 +1,2 @@ +require ('./http_json.js'); +require ('./ServiceConfiguration.js');