Skip to content
Open
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
29 changes: 9 additions & 20 deletions lib/pushgateway.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use strict';

const url = require('url');
const http = require('http');
const https = require('https');
const { gzipSync } = require('zlib');
Expand Down Expand Up @@ -45,33 +44,27 @@ class Pushgateway {
return useGateway.call(this, 'DELETE', params.jobName, params.groupings);
}
}

async function useGateway(method, job, groupings) {
// `URL` first added in v6.13.0
// eslint-disable-next-line n/no-deprecated-api
const gatewayUrlParsed = url.parse(this.gatewayUrl);
// `URL` is a global since Node.js v10 - no `require('url')` needed.
const requestParams = new URL(this.gatewayUrl);
const gatewayUrlPath =
gatewayUrlParsed.pathname && gatewayUrlParsed.pathname !== '/'
? gatewayUrlParsed.pathname
requestParams.pathname && requestParams.pathname !== '/'
? requestParams.pathname
: '';
const jobPath = job
? `/job/${encodeURIComponent(job)}${generateGroupings(groupings)}`
: '';
const path = `${gatewayUrlPath}/metrics${jobPath}`;
requestParams.pathname = `${gatewayUrlPath}/metrics${jobPath}`;

// eslint-disable-next-line n/no-deprecated-api
const target = url.resolve(this.gatewayUrl, path);
// eslint-disable-next-line n/no-deprecated-api
const requestParams = url.parse(target);
const httpModule = isHttps(requestParams.href) ? https : http;
const options = Object.assign(requestParams, this.requestOptions, {
method,
});
const httpModule = requestParams.protocol === 'https:' ? https : http;
const options = { ...this.requestOptions, method };

return new Promise((resolve, reject) => {
if (method === 'DELETE' && options.headers) {
delete options.headers['Content-Encoding'];
}
const req = httpModule.request(options, resp => {
const req = httpModule.request(requestParams, options, resp => {
let body = '';
resp.setEncoding('utf8');
resp.on('data', chunk => {
Expand Down Expand Up @@ -129,8 +122,4 @@ function generateGroupings(groupings) {
.join('');
}

function isHttps(href) {
return href.search(/^https/) !== -1;
}

module.exports = Pushgateway;
37 changes: 37 additions & 0 deletions test/__snapshots__/pushgatewayWithPathTest.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing

exports[`pushgateway with path and OpenMetrics registry global registry pins the http.request(url, options) call shape (no legacy options translation) 1`] = `
{
"options": {
"method": "PUT",
},
"url": "http://192.168.99.100:9091/path/metrics/job/testJob",
}
`;

exports[`pushgateway with path and OpenMetrics registry registry instance pins the http.request(url, options) call shape (no legacy options translation) 1`] = `
{
"options": {
"method": "PUT",
},
"url": "http://192.168.99.100:9091/path/metrics/job/testJob",
}
`;

exports[`pushgateway with path and Prometheus registry global registry pins the http.request(url, options) call shape (no legacy options translation) 1`] = `
{
"options": {
"method": "PUT",
},
"url": "http://192.168.99.100:9091/path/metrics/job/testJob",
}
`;

exports[`pushgateway with path and Prometheus registry registry instance pins the http.request(url, options) call shape (no legacy options translation) 1`] = `
{
"options": {
"method": "PUT",
},
"url": "http://192.168.99.100:9091/path/metrics/job/testJob",
}
`;
77 changes: 48 additions & 29 deletions test/pushgatewayWithPathTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,27 +37,29 @@ describe.each([
instance.pushAdd({ jobName: 'testJob' });

expect(mockHttp).toHaveBeenCalledTimes(1);
const invocation = mockHttp.mock.calls[0][0];
expect(invocation.method).toEqual('POST');
expect(invocation.path).toEqual('/path/metrics/job/testJob');
const [requestUrl, requestOptions] = mockHttp.mock.calls[0];
expect(requestOptions.method).toEqual('POST');
expect(requestUrl.pathname).toEqual('/path/metrics/job/testJob');
});

it('should use groupings', () => {
instance.pushAdd({ jobName: 'testJob', groupings: { key: 'value' } });

expect(mockHttp).toHaveBeenCalledTimes(1);
const invocation = mockHttp.mock.calls[0][0];
expect(invocation.method).toEqual('POST');
expect(invocation.path).toEqual('/path/metrics/job/testJob/key/value');
const [requestUrl, requestOptions] = mockHttp.mock.calls[0];
expect(requestOptions.method).toEqual('POST');
expect(requestUrl.pathname).toEqual(
'/path/metrics/job/testJob/key/value',
);
});

it('should escape groupings', () => {
instance.pushAdd({ jobName: 'testJob', groupings: { key: 'va&lue' } });

expect(mockHttp).toHaveBeenCalledTimes(1);
const invocation = mockHttp.mock.calls[0][0];
expect(invocation.method).toEqual('POST');
expect(invocation.path).toEqual(
const [requestUrl, requestOptions] = mockHttp.mock.calls[0];
expect(requestOptions.method).toEqual('POST');
expect(requestUrl.pathname).toEqual(
'/path/metrics/job/testJob/key/va%26lue',
);
});
Expand All @@ -68,18 +70,18 @@ describe.each([
instance.push({ jobName: 'testJob' });

expect(mockHttp).toHaveBeenCalledTimes(1);
const invocation = mockHttp.mock.calls[0][0];
expect(invocation.method).toEqual('PUT');
expect(invocation.path).toEqual('/path/metrics/job/testJob');
const [requestUrl, requestOptions] = mockHttp.mock.calls[0];
expect(requestOptions.method).toEqual('PUT');
expect(requestUrl.pathname).toEqual('/path/metrics/job/testJob');
});

it('should uri encode url', () => {
instance.push({ jobName: 'test&Job' });

expect(mockHttp).toHaveBeenCalledTimes(1);
const invocation = mockHttp.mock.calls[0][0];
expect(invocation.method).toEqual('PUT');
expect(invocation.path).toEqual('/path/metrics/job/test%26Job');
const [requestUrl, requestOptions] = mockHttp.mock.calls[0];
expect(requestOptions.method).toEqual('PUT');
expect(requestUrl.pathname).toEqual('/path/metrics/job/test%26Job');
});
});

Expand All @@ -88,9 +90,9 @@ describe.each([
instance.delete({ jobName: 'testJob' });

expect(mockHttp).toHaveBeenCalledTimes(1);
const invocation = mockHttp.mock.calls[0][0];
expect(invocation.method).toEqual('DELETE');
expect(invocation.path).toEqual('/path/metrics/job/testJob');
const [requestUrl, requestOptions] = mockHttp.mock.calls[0];
expect(requestOptions.method).toEqual('DELETE');
expect(requestUrl.pathname).toEqual('/path/metrics/job/testJob');
});
});

Expand All @@ -111,27 +113,30 @@ describe.each([
instance.pushAdd({ jobName: 'testJob' });

expect(mockHttp).toHaveBeenCalledTimes(1);
const invocation = mockHttp.mock.calls[0][0];
expect(invocation.method).toEqual('POST');
expect(invocation.auth).toEqual(auth);
const [requestUrl, requestOptions] = mockHttp.mock.calls[0];
expect(requestOptions.method).toEqual('POST');
expect(requestUrl.username).toEqual(USERNAME);
expect(requestUrl.password).toEqual(PASSWORD);
});

it('push should send PUT request with basic auth data', () => {
instance.push({ jobName: 'testJob' });

expect(mockHttp).toHaveBeenCalledTimes(1);
const invocation = mockHttp.mock.calls[0][0];
expect(invocation.method).toEqual('PUT');
expect(invocation.auth).toEqual(auth);
const [requestUrl, requestOptions] = mockHttp.mock.calls[0];
expect(requestOptions.method).toEqual('PUT');
expect(requestUrl.username).toEqual(USERNAME);
expect(requestUrl.password).toEqual(PASSWORD);
});

it('delete should send DELETE request with basic auth data', () => {
instance.delete({ jobName: 'testJob' });

expect(mockHttp).toHaveBeenCalledTimes(1);
const invocation = mockHttp.mock.calls[0][0];
expect(invocation.method).toEqual('DELETE');
expect(invocation.auth).toEqual(auth);
const [requestUrl, requestOptions] = mockHttp.mock.calls[0];
expect(requestOptions.method).toEqual('DELETE');
expect(requestUrl.username).toEqual(USERNAME);
expect(requestUrl.password).toEqual(PASSWORD);
});
});

Expand All @@ -149,8 +154,22 @@ describe.each([
instance.push({ jobName: 'testJob' });

expect(mockHttp).toHaveBeenCalledTimes(1);
const invocation = mockHttp.mock.calls[0][0];
expect(invocation.headers).toEqual({ 'unit-test': '1' });
const [, requestOptions] = mockHttp.mock.calls[0];
expect(requestOptions.headers).toEqual({ 'unit-test': '1' });
});

it('pins the http.request(url, options) call shape (no legacy options translation)', () => {
instance.push({ jobName: 'testJob' });

expect(mockHttp).toHaveBeenCalledTimes(1);
const [requestUrl, requestOptions] = mockHttp.mock.calls[0];

expect(requestUrl).toBeInstanceOf(URL);

expect({
url: requestUrl.toString(),
options: requestOptions,
}).toMatchSnapshot();
});
};
describe('global registry', () => {
Expand Down
Loading