From f2dcec6b17e12ea67344609e6e166de961903df4 Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Mon, 11 Jan 2021 14:08:31 -0500 Subject: [PATCH 1/4] chore: use local server for http integration tests (#1808) --- .../test/integrations/http-enable.test.ts | 114 ++++++++++----- .../test/integrations/https-enable.test.ts | 130 +++++++++++++----- .../test/functionals/http-package.test.ts | 49 ++++++- .../test/integrations/http-enable.test.ts | 110 ++++++++++----- .../test/functionals/https-package.test.ts | 66 +++++++-- .../test/integrations/https-enable.test.ts | 130 +++++++++++++----- 6 files changed, 447 insertions(+), 152 deletions(-) diff --git a/packages/opentelemetry-instrumentation-http/test/integrations/http-enable.test.ts b/packages/opentelemetry-instrumentation-http/test/integrations/http-enable.test.ts index f0ba3ec005..6775f9d9e0 100644 --- a/packages/opentelemetry-instrumentation-http/test/integrations/http-enable.test.ts +++ b/packages/opentelemetry-instrumentation-http/test/integrations/http-enable.test.ts @@ -45,6 +45,7 @@ instrumentation.disable(); import * as http from 'http'; import { httpRequest } from '../utils/httpRequest'; import { DummyPropagation } from '../utils/DummyPropagation'; +import { Socket } from 'net'; const protocol = 'http'; const serverPort = 32345; @@ -56,6 +57,47 @@ const customAttributeFunction = (span: Span): void => { }; describe('HttpInstrumentation Integration tests', () => { + let mockServerPort = 0; + let mockServer: http.Server; + const sockets: Array = []; + before(done => { + mockServer = http.createServer((req, res) => { + res.statusCode = 200; + res.setHeader('content-type', 'application/json'); + res.write( + JSON.stringify({ + success: true, + }) + ); + res.end(); + }); + + mockServer.listen(0, () => { + const addr = mockServer.address(); + if (addr == null) { + done(new Error('unexpected addr null')); + return; + } + + if (typeof addr === 'string') { + done(new Error(`unexpected addr ${addr}`)); + return; + } + + if (addr.port <= 0) { + done(new Error('Could not get port')); + return; + } + mockServerPort = addr.port; + done(); + }); + }); + + after(done => { + sockets.forEach(s => s.destroy()); + mockServer.close(done); + }); + beforeEach(() => { memoryExporter.reset(); context.setGlobalContextManager(new AsyncHooksContextManager().enable()); @@ -115,13 +157,14 @@ describe('HttpInstrumentation Integration tests', () => { assert.strictEqual(spans.length, 0); const result = await httpRequest.get( - `${protocol}://google.fr/?query=test` + `${protocol}://localhost:${mockServerPort}/?query=test` ); spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: result.statusCode!, httpMethod: 'GET', pathname: '/', @@ -131,7 +174,7 @@ describe('HttpInstrumentation Integration tests', () => { component: 'http', }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTP GET'); assertSpan(span, SpanKind.CLIENT, validations); }); @@ -141,13 +184,14 @@ describe('HttpInstrumentation Integration tests', () => { assert.strictEqual(spans.length, 0); const result = await httpRequest.get( - new url.URL(`${protocol}://google.fr/?query=test`) + new url.URL(`${protocol}://localhost:${mockServerPort}/?query=test`) ); spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: result.statusCode!, httpMethod: 'GET', pathname: '/', @@ -157,7 +201,7 @@ describe('HttpInstrumentation Integration tests', () => { component: 'http', }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTP GET'); assertSpan(span, SpanKind.CLIENT, validations); }); @@ -167,16 +211,17 @@ describe('HttpInstrumentation Integration tests', () => { assert.strictEqual(spans.length, 0); const result = await httpRequest.get( - new url.URL(`${protocol}://google.fr/?query=test`), + new url.URL(`${protocol}://localhost:${mockServerPort}/?query=test`), { headers: { 'x-foo': 'foo' }, } ); spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: result.statusCode!, httpMethod: 'GET', pathname: '/', @@ -186,7 +231,7 @@ describe('HttpInstrumentation Integration tests', () => { component: 'http', }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTP GET'); assert.strictEqual(result.reqHeaders['x-foo'], 'foo'); assert.strictEqual(span.attributes[HttpAttribute.HTTP_FLAVOR], '1.1'); @@ -198,11 +243,14 @@ describe('HttpInstrumentation Integration tests', () => { }); it('custom attributes should show up on client spans', async () => { - const result = await httpRequest.get(`${protocol}://google.fr/`); + const result = await httpRequest.get( + `${protocol}://localhost:${mockServerPort}/` + ); const spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: result.statusCode!, httpMethod: 'GET', pathname: '/', @@ -211,7 +259,7 @@ describe('HttpInstrumentation Integration tests', () => { component: 'http', }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTP GET'); assert.strictEqual(span.attributes['span kind'], SpanKind.CLIENT); assertSpan(span, SpanKind.CLIENT, validations); @@ -222,15 +270,16 @@ describe('HttpInstrumentation Integration tests', () => { assert.strictEqual(spans.length, 0); const options = Object.assign( { headers: { Expect: '100-continue' } }, - url.parse(`${protocol}://google.fr/`) + url.parse(`${protocol}://localhost:${mockServerPort}/`) ); const result = await httpRequest.get(options); spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', - httpStatusCode: 301, + hostname: 'localhost', + httpStatusCode: 200, httpMethod: 'GET', pathname: '/', resHeaders: result.resHeaders, @@ -238,20 +287,13 @@ describe('HttpInstrumentation Integration tests', () => { component: 'http', }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTP GET'); - - try { - assertSpan(span, SpanKind.CLIENT, validations); - } catch (error) { - // temporary redirect is also correct - validations.httpStatusCode = 307; - assertSpan(span, SpanKind.CLIENT, validations); - } + assertSpan(span, SpanKind.CLIENT, validations); }); for (const headers of [ - { Expect: '100-continue', 'user-agent': 'http-instrumentation-test' }, - { 'user-agent': 'http-instrumentation-test' }, + { Expect: '100-continue', 'user-agent': 'http-plugin-test' }, + { 'user-agent': 'http-plugin-test' }, ]) { it(`should create a span for GET requests and add propagation when using the following signature: get(url, options, callback) and following headers: ${JSON.stringify( headers @@ -269,7 +311,7 @@ describe('HttpInstrumentation Integration tests', () => { assert.strictEqual(spans.length, 0); const options = { headers }; const req = http.get( - `${protocol}://google.fr/`, + `${protocol}://localhost:${mockServerPort}/`, options, (resp: http.IncomingMessage) => { const res = (resp as unknown) as http.IncomingMessage & { @@ -281,7 +323,7 @@ describe('HttpInstrumentation Integration tests', () => { }); resp.on('end', () => { validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: 301, httpMethod: 'GET', pathname: '/', @@ -298,8 +340,10 @@ describe('HttpInstrumentation Integration tests', () => { req.on('close', () => { const spans = memoryExporter.getFinishedSpans(); - assert.strictEqual(spans.length, 1); - assert.strictEqual(spans[0].name, 'HTTP GET'); + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); + assert.strictEqual(spans.length, 2); + assert.strictEqual(span.name, 'HTTP GET'); assert.ok(data); assert.ok(validations.reqHeaders[DummyPropagation.TRACE_CONTEXT_KEY]); assert.ok(validations.reqHeaders[DummyPropagation.SPAN_CONTEXT_KEY]); diff --git a/packages/opentelemetry-instrumentation-http/test/integrations/https-enable.test.ts b/packages/opentelemetry-instrumentation-http/test/integrations/https-enable.test.ts index 880c2ec0f6..5714414cc0 100644 --- a/packages/opentelemetry-instrumentation-http/test/integrations/https-enable.test.ts +++ b/packages/opentelemetry-instrumentation-http/test/integrations/https-enable.test.ts @@ -27,6 +27,9 @@ import { } from '@opentelemetry/semantic-conventions'; import * as assert from 'assert'; import * as http from 'http'; +import * as fs from 'fs'; +import * as path from 'path'; +import { Socket } from 'net'; import { assertSpan } from '../utils/assertSpan'; import * as url from 'url'; import * as utils from '../utils/utils'; @@ -57,6 +60,57 @@ export const customAttributeFunction = (span: Span): void => { }; describe('HttpsInstrumentation Integration tests', () => { + let mockServerPort = 0; + let mockServer: https.Server; + const sockets: Array = []; + before(done => { + mockServer = https.createServer( + { + key: fs.readFileSync( + path.join(__dirname, '..', 'fixtures', 'server-key.pem') + ), + cert: fs.readFileSync( + path.join(__dirname, '..', 'fixtures', 'server-cert.pem') + ), + }, + (req, res) => { + res.statusCode = 200; + res.setHeader('content-type', 'application/json'); + res.write( + JSON.stringify({ + success: true, + }) + ); + res.end(); + } + ); + + mockServer.listen(0, () => { + const addr = mockServer.address(); + if (addr == null) { + done(new Error('unexpected addr null')); + return; + } + + if (typeof addr === 'string') { + done(new Error(`unexpected addr ${addr}`)); + return; + } + + if (addr.port <= 0) { + done(new Error('Could not get port')); + return; + } + mockServerPort = addr.port; + done(); + }); + }); + + after(done => { + sockets.forEach(s => s.destroy()); + mockServer.close(done); + }); + beforeEach(() => { memoryExporter.reset(); context.setGlobalContextManager(new AsyncHooksContextManager().enable()); @@ -116,13 +170,14 @@ describe('HttpsInstrumentation Integration tests', () => { assert.strictEqual(spans.length, 0); const result = await httpsRequest.get( - `${protocol}://google.fr/?query=test` + `${protocol}://localhost:${mockServerPort}/?query=test` ); spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: result.statusCode!, httpMethod: 'GET', pathname: '/', @@ -132,7 +187,7 @@ describe('HttpsInstrumentation Integration tests', () => { component: 'https', }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTPS GET'); assertSpan(span, SpanKind.CLIENT, validations); }); @@ -142,13 +197,14 @@ describe('HttpsInstrumentation Integration tests', () => { assert.strictEqual(spans.length, 0); const result = await httpsRequest.get( - new url.URL(`${protocol}://google.fr/?query=test`) + new url.URL(`${protocol}://localhost:${mockServerPort}/?query=test`) ); spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: result.statusCode!, httpMethod: 'GET', pathname: '/', @@ -158,7 +214,7 @@ describe('HttpsInstrumentation Integration tests', () => { component: 'https', }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTPS GET'); assertSpan(span, SpanKind.CLIENT, validations); }); @@ -168,14 +224,17 @@ describe('HttpsInstrumentation Integration tests', () => { assert.strictEqual(spans.length, 0); const result = await httpsRequest.get( - new url.URL(`${protocol}://google.fr/?query=test`), - { headers: { 'x-foo': 'foo' } } + new url.URL(`${protocol}://localhost:${mockServerPort}/?query=test`), + { + headers: { 'x-foo': 'foo' }, + } ); spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: result.statusCode!, httpMethod: 'GET', pathname: '/', @@ -185,7 +244,7 @@ describe('HttpsInstrumentation Integration tests', () => { component: 'https', }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTPS GET'); assert.strictEqual(result.reqHeaders['x-foo'], 'foo'); assert.strictEqual(span.attributes[HttpAttribute.HTTP_FLAVOR], '1.1'); @@ -197,11 +256,14 @@ describe('HttpsInstrumentation Integration tests', () => { }); it('custom attributes should show up on client spans', async () => { - const result = await httpsRequest.get(`${protocol}://google.fr/`); + const result = await httpsRequest.get( + `${protocol}://localhost:${mockServerPort}/` + ); const spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: result.statusCode!, httpMethod: 'GET', pathname: '/', @@ -210,7 +272,7 @@ describe('HttpsInstrumentation Integration tests', () => { component: 'https', }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTPS GET'); assert.strictEqual(span.attributes['span kind'], SpanKind.CLIENT); assertSpan(span, SpanKind.CLIENT, validations); @@ -221,15 +283,16 @@ describe('HttpsInstrumentation Integration tests', () => { assert.strictEqual(spans.length, 0); const options = Object.assign( { headers: { Expect: '100-continue' } }, - url.parse(`${protocol}://google.fr/`) + url.parse(`${protocol}://localhost:${mockServerPort}/`) ); const result = await httpsRequest.get(options); spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', - httpStatusCode: 301, + hostname: 'localhost', + httpStatusCode: 200, httpMethod: 'GET', pathname: '/', resHeaders: result.resHeaders, @@ -237,20 +300,13 @@ describe('HttpsInstrumentation Integration tests', () => { component: 'https', }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTPS GET'); - - try { - assertSpan(span, SpanKind.CLIENT, validations); - } catch (error) { - // temporary redirect is also correct - validations.httpStatusCode = 307; - assertSpan(span, SpanKind.CLIENT, validations); - } + assertSpan(span, SpanKind.CLIENT, validations); }); for (const headers of [ - { Expect: '100-continue', 'user-agent': 'https-instrumentation-test' }, - { 'user-agent': 'https-instrumentation-test' }, + { Expect: '100-continue', 'user-agent': 'http-plugin-test' }, + { 'user-agent': 'http-plugin-test' }, ]) { it(`should create a span for GET requests and add propagation when using the following signature: get(url, options, callback) and following headers: ${JSON.stringify( headers @@ -268,7 +324,7 @@ describe('HttpsInstrumentation Integration tests', () => { assert.strictEqual(spans.length, 0); const options = { headers }; const req = https.get( - `${protocol}://google.fr/`, + `${protocol}://localhost:${mockServerPort}/`, options, (resp: http.IncomingMessage) => { const res = (resp as unknown) as http.IncomingMessage & { @@ -280,7 +336,7 @@ describe('HttpsInstrumentation Integration tests', () => { }); resp.on('end', () => { validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: 301, httpMethod: 'GET', pathname: '/', @@ -297,8 +353,10 @@ describe('HttpsInstrumentation Integration tests', () => { req.on('close', () => { const spans = memoryExporter.getFinishedSpans(); - assert.strictEqual(spans.length, 1); - assert.strictEqual(spans[0].name, 'HTTPS GET'); + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); + assert.strictEqual(spans.length, 2); + assert.strictEqual(span.name, 'HTTPS GET'); assert.ok(data); assert.ok(validations.reqHeaders[DummyPropagation.TRACE_CONTEXT_KEY]); assert.ok(validations.reqHeaders[DummyPropagation.SPAN_CONTEXT_KEY]); diff --git a/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts b/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts index 31bb06f48a..85396d33b0 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts @@ -25,6 +25,7 @@ import * as assert from 'assert'; import axios, { AxiosResponse } from 'axios'; import * as got from 'got'; import * as http from 'http'; +import { Socket } from 'net'; import * as nock from 'nock'; import * as path from 'path'; import * as request from 'request-promise-native'; @@ -40,6 +41,47 @@ const memoryExporter = new InMemorySpanExporter(); const protocol = 'http'; describe('Packages', () => { + let mockServerPort = 0; + let mockServer: http.Server; + const sockets: Array = []; + before(done => { + mockServer = http.createServer((req, res) => { + res.statusCode = 200; + res.setHeader('content-type', 'application/json'); + res.write( + JSON.stringify({ + success: true, + }) + ); + res.end(); + }); + + mockServer.listen(0, () => { + const addr = mockServer.address(); + if (addr == null) { + done(new Error('unexpected addr null')); + return; + } + + if (typeof addr === 'string') { + done(new Error(`unexpected addr ${addr}`)); + return; + } + + if (addr.port <= 0) { + done(new Error('Could not get port')); + return; + } + mockServerPort = addr.port; + done(); + }); + }); + + after(done => { + sockets.forEach(s => s.destroy()); + mockServer.close(done); + }); + beforeEach(() => { context.setGlobalContextManager(new AsyncHooksContextManager().enable()); }); @@ -92,7 +134,7 @@ describe('Packages', () => { } const urlparsed = url.parse( - `${protocol}://www.google.com/search?q=axios&oq=axios&aqs=chrome.0.69i59l2j0l3j69i60.811j0j7&sourceid=chrome&ie=UTF-8` + `${protocol}://localhost:${mockServerPort}/search?q=axios&oq=axios&aqs=chrome.0.69i59l2j0l3j69i60.811j0j7&sourceid=chrome&ie=UTF-8` ); const result = await httpPackage.get(urlparsed.href!); if (!resHeaders) { @@ -100,7 +142,8 @@ describe('Packages', () => { resHeaders = res.headers; } const spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { hostname: urlparsed.hostname!, httpStatusCode: 200, @@ -111,7 +154,7 @@ describe('Packages', () => { component: plugin.component, }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTP GET'); switch (name) { diff --git a/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts b/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts index 383a4b3b45..9552c2a97c 100644 --- a/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts +++ b/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts @@ -34,6 +34,7 @@ import { } from '@opentelemetry/tracing'; import { HttpPluginConfig } from '../../src/types'; import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; +import { Socket } from 'net'; const protocol = 'http'; const serverPort = 32345; const hostname = 'localhost'; @@ -44,6 +45,47 @@ export const customAttributeFunction = (span: Span): void => { }; describe('HttpPlugin Integration tests', () => { + let mockServerPort = 0; + let mockServer: http.Server; + const sockets: Array = []; + before(done => { + mockServer = http.createServer((req, res) => { + res.statusCode = 200; + res.setHeader('content-type', 'application/json'); + res.write( + JSON.stringify({ + success: true, + }) + ); + res.end(); + }); + + mockServer.listen(0, () => { + const addr = mockServer.address(); + if (addr == null) { + done(new Error('unexpected addr null')); + return; + } + + if (typeof addr === 'string') { + done(new Error(`unexpected addr ${addr}`)); + return; + } + + if (addr.port <= 0) { + done(new Error('Could not get port')); + return; + } + mockServerPort = addr.port; + done(); + }); + }); + + after(done => { + sockets.forEach(s => s.destroy()); + mockServer.close(done); + }); + beforeEach(() => { memoryExporter.reset(); context.setGlobalContextManager(new AsyncHooksContextManager().enable()); @@ -104,13 +146,14 @@ describe('HttpPlugin Integration tests', () => { assert.strictEqual(spans.length, 0); const result = await httpRequest.get( - `${protocol}://google.fr/?query=test` + `${protocol}://localhost:${mockServerPort}/?query=test` ); spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: result.statusCode!, httpMethod: 'GET', pathname: '/', @@ -120,7 +163,7 @@ describe('HttpPlugin Integration tests', () => { component: plugin.component, }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTP GET'); assertSpan(span, SpanKind.CLIENT, validations); }); @@ -130,13 +173,14 @@ describe('HttpPlugin Integration tests', () => { assert.strictEqual(spans.length, 0); const result = await httpRequest.get( - new url.URL(`${protocol}://google.fr/?query=test`) + new url.URL(`${protocol}://localhost:${mockServerPort}/?query=test`) ); spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: result.statusCode!, httpMethod: 'GET', pathname: '/', @@ -146,7 +190,7 @@ describe('HttpPlugin Integration tests', () => { component: plugin.component, }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTP GET'); assertSpan(span, SpanKind.CLIENT, validations); }); @@ -156,16 +200,17 @@ describe('HttpPlugin Integration tests', () => { assert.strictEqual(spans.length, 0); const result = await httpRequest.get( - new url.URL(`${protocol}://google.fr/?query=test`), + new url.URL(`${protocol}://localhost:${mockServerPort}/?query=test`), { headers: { 'x-foo': 'foo' }, } ); spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: result.statusCode!, httpMethod: 'GET', pathname: '/', @@ -175,7 +220,7 @@ describe('HttpPlugin Integration tests', () => { component: plugin.component, }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTP GET'); assert.strictEqual(result.reqHeaders['x-foo'], 'foo'); assert.strictEqual(span.attributes[HttpAttribute.HTTP_FLAVOR], '1.1'); @@ -187,11 +232,14 @@ describe('HttpPlugin Integration tests', () => { }); it('custom attributes should show up on client spans', async () => { - const result = await httpRequest.get(`${protocol}://google.fr/`); + const result = await httpRequest.get( + `${protocol}://localhost:${mockServerPort}/` + ); const spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: result.statusCode!, httpMethod: 'GET', pathname: '/', @@ -200,7 +248,7 @@ describe('HttpPlugin Integration tests', () => { component: plugin.component, }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTP GET'); assert.strictEqual(span.attributes['span kind'], SpanKind.CLIENT); assertSpan(span, SpanKind.CLIENT, validations); @@ -211,15 +259,16 @@ describe('HttpPlugin Integration tests', () => { assert.strictEqual(spans.length, 0); const options = Object.assign( { headers: { Expect: '100-continue' } }, - url.parse(`${protocol}://google.fr/`) + url.parse(`${protocol}://localhost:${mockServerPort}/`) ); const result = await httpRequest.get(options); spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', - httpStatusCode: 301, + hostname: 'localhost', + httpStatusCode: 200, httpMethod: 'GET', pathname: '/', resHeaders: result.resHeaders, @@ -227,16 +276,9 @@ describe('HttpPlugin Integration tests', () => { component: plugin.component, }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTP GET'); - - try { - assertSpan(span, SpanKind.CLIENT, validations); - } catch (error) { - // temporary redirect is also correct - validations.httpStatusCode = 307; - assertSpan(span, SpanKind.CLIENT, validations); - } + assertSpan(span, SpanKind.CLIENT, validations); }); for (const headers of [ { Expect: '100-continue', 'user-agent': 'http-plugin-test' }, @@ -258,7 +300,7 @@ describe('HttpPlugin Integration tests', () => { assert.strictEqual(spans.length, 0); const options = { headers }; const req = http.get( - `${protocol}://google.fr/`, + `${protocol}://localhost:${mockServerPort}/`, options, (resp: http.IncomingMessage) => { const res = (resp as unknown) as http.IncomingMessage & { @@ -270,7 +312,7 @@ describe('HttpPlugin Integration tests', () => { }); resp.on('end', () => { validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: 301, httpMethod: 'GET', pathname: '/', @@ -287,8 +329,10 @@ describe('HttpPlugin Integration tests', () => { req.on('close', () => { const spans = memoryExporter.getFinishedSpans(); - assert.strictEqual(spans.length, 1); - assert.strictEqual(spans[0].name, 'HTTP GET'); + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); + assert.strictEqual(spans.length, 2); + assert.strictEqual(span.name, 'HTTP GET'); assert.ok(data); assert.ok(validations.reqHeaders[DummyPropagation.TRACE_CONTEXT_KEY]); assert.ok(validations.reqHeaders[DummyPropagation.SPAN_CONTEXT_KEY]); diff --git a/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts b/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts index daf3ac7e9e..8fed01b8fe 100644 --- a/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts +++ b/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts @@ -25,6 +25,7 @@ import { import * as assert from 'assert'; import axios, { AxiosResponse } from 'axios'; import * as got from 'got'; +import * as fs from 'fs'; import * as http from 'http'; import * as https from 'https'; import * as nock from 'nock'; @@ -35,6 +36,7 @@ import * as url from 'url'; import { plugin } from '../../src/https'; import { assertSpan } from '../utils/assertSpan'; import { DummyPropagation } from '../utils/DummyPropagation'; +import { Socket } from 'net'; const memoryExporter = new InMemorySpanExporter(); @@ -43,6 +45,57 @@ export const customAttributeFunction = (span: Span): void => { }; describe('Packages', () => { + let mockServerPort = 0; + let mockServer: https.Server; + const sockets: Array = []; + before(done => { + mockServer = https.createServer( + { + key: fs.readFileSync( + path.join(__dirname, '..', 'fixtures', 'server-key.pem') + ), + cert: fs.readFileSync( + path.join(__dirname, '..', 'fixtures', 'server-cert.pem') + ), + }, + (req, res) => { + res.statusCode = 200; + res.setHeader('content-type', 'application/json'); + res.write( + JSON.stringify({ + success: true, + }) + ); + res.end(); + } + ); + + mockServer.listen(0, () => { + const addr = mockServer.address(); + if (addr == null) { + done(new Error('unexpected addr null')); + return; + } + + if (typeof addr === 'string') { + done(new Error(`unexpected addr ${addr}`)); + return; + } + + if (addr.port <= 0) { + done(new Error('Could not get port')); + return; + } + mockServerPort = addr.port; + done(); + }); + }); + + after(done => { + sockets.forEach(s => s.destroy()); + mockServer.close(done); + }); + beforeEach(() => { memoryExporter.reset(); context.setGlobalContextManager(new AsyncHooksContextManager().enable()); @@ -94,13 +147,7 @@ describe('Packages', () => { } const urlparsed = url.parse( - name === 'got' && process.versions.node.startsWith('12') - ? // there is an issue with got 9.6 version and node 12 when redirecting so url above will not work - // https://github.com/nock/nock/pull/1551 - // https://github.com/sindresorhus/got/commit/bf1aa5492ae2bc78cbbec6b7d764906fb156e6c2#diff-707a4781d57c42085155dcb27edb9ccbR258 - // TODO: check if this is still the case when new version - 'https://www.google.com' - : 'https://www.google.com/search?q=axios&oq=axios&aqs=chrome.0.69i59l2j0l3j69i60.811j0j7&sourceid=chrome&ie=UTF-8' + `https://localhost:${mockServerPort}/?query=test` ); const result = await httpPackage.get(urlparsed.href!); if (!resHeaders) { @@ -108,7 +155,8 @@ describe('Packages', () => { resHeaders = res.headers; } const spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { hostname: urlparsed.hostname!, httpStatusCode: 200, @@ -119,7 +167,7 @@ describe('Packages', () => { component: plugin.component, }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTP GET'); switch (name) { diff --git a/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts b/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts index 3fc48cdcad..74a3bbea16 100644 --- a/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts +++ b/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts @@ -22,6 +22,8 @@ import { } from '@opentelemetry/semantic-conventions'; import * as assert from 'assert'; import * as http from 'http'; +import * as fs from 'fs'; +import * as path from 'path'; import * as https from 'https'; import { plugin } from '../../src/https'; import { assertSpan } from '../utils/assertSpan'; @@ -35,6 +37,7 @@ import { SimpleSpanProcessor, } from '@opentelemetry/tracing'; import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; +import { Socket } from 'net'; const protocol = 'https'; const serverPort = 42345; @@ -46,6 +49,57 @@ export const customAttributeFunction = (span: Span): void => { }; describe('HttpsPlugin Integration tests', () => { + let mockServerPort = 0; + let mockServer: https.Server; + const sockets: Array = []; + before(done => { + mockServer = https.createServer( + { + key: fs.readFileSync( + path.join(__dirname, '..', 'fixtures', 'server-key.pem') + ), + cert: fs.readFileSync( + path.join(__dirname, '..', 'fixtures', 'server-cert.pem') + ), + }, + (req, res) => { + res.statusCode = 200; + res.setHeader('content-type', 'application/json'); + res.write( + JSON.stringify({ + success: true, + }) + ); + res.end(); + } + ); + + mockServer.listen(0, () => { + const addr = mockServer.address(); + if (addr == null) { + done(new Error('unexpected addr null')); + return; + } + + if (typeof addr === 'string') { + done(new Error(`unexpected addr ${addr}`)); + return; + } + + if (addr.port <= 0) { + done(new Error('Could not get port')); + return; + } + mockServerPort = addr.port; + done(); + }); + }); + + after(done => { + sockets.forEach(s => s.destroy()); + mockServer.close(done); + }); + beforeEach(() => { memoryExporter.reset(); context.setGlobalContextManager(new AsyncHooksContextManager().enable()); @@ -111,13 +165,14 @@ describe('HttpsPlugin Integration tests', () => { assert.strictEqual(spans.length, 0); const result = await httpsRequest.get( - `${protocol}://google.fr/?query=test` + `${protocol}://localhost:${mockServerPort}/?query=test` ); spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: result.statusCode!, httpMethod: 'GET', pathname: '/', @@ -127,7 +182,7 @@ describe('HttpsPlugin Integration tests', () => { component: plugin.component, }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTP GET'); assertSpan(span, SpanKind.CLIENT, validations); }); @@ -137,13 +192,14 @@ describe('HttpsPlugin Integration tests', () => { assert.strictEqual(spans.length, 0); const result = await httpsRequest.get( - new url.URL(`${protocol}://google.fr/?query=test`) + new url.URL(`${protocol}://localhost:${mockServerPort}/?query=test`) ); spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: result.statusCode!, httpMethod: 'GET', pathname: '/', @@ -153,7 +209,7 @@ describe('HttpsPlugin Integration tests', () => { component: plugin.component, }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTP GET'); assertSpan(span, SpanKind.CLIENT, validations); }); @@ -163,14 +219,17 @@ describe('HttpsPlugin Integration tests', () => { assert.strictEqual(spans.length, 0); const result = await httpsRequest.get( - new url.URL(`${protocol}://google.fr/?query=test`), - { headers: { 'x-foo': 'foo' } } + new url.URL(`${protocol}://localhost:${mockServerPort}/?query=test`), + { + headers: { 'x-foo': 'foo' }, + } ); spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: result.statusCode!, httpMethod: 'GET', pathname: '/', @@ -180,7 +239,7 @@ describe('HttpsPlugin Integration tests', () => { component: plugin.component, }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTP GET'); assert.strictEqual(result.reqHeaders['x-foo'], 'foo'); assert.strictEqual(span.attributes[HttpAttribute.HTTP_FLAVOR], '1.1'); @@ -192,11 +251,14 @@ describe('HttpsPlugin Integration tests', () => { }); it('custom attributes should show up on client spans', async () => { - const result = await httpsRequest.get(`${protocol}://google.fr/`); + const result = await httpsRequest.get( + `${protocol}://localhost:${mockServerPort}/` + ); const spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: result.statusCode!, httpMethod: 'GET', pathname: '/', @@ -205,7 +267,7 @@ describe('HttpsPlugin Integration tests', () => { component: plugin.component, }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTP GET'); assert.strictEqual(span.attributes['span kind'], SpanKind.CLIENT); assertSpan(span, SpanKind.CLIENT, validations); @@ -216,15 +278,16 @@ describe('HttpsPlugin Integration tests', () => { assert.strictEqual(spans.length, 0); const options = Object.assign( { headers: { Expect: '100-continue' } }, - url.parse(`${protocol}://google.fr/`) + url.parse(`${protocol}://localhost:${mockServerPort}/`) ); const result = await httpsRequest.get(options); spans = memoryExporter.getFinishedSpans(); - const span = spans[0]; + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); const validations = { - hostname: 'google.fr', - httpStatusCode: 301, + hostname: 'localhost', + httpStatusCode: 200, httpMethod: 'GET', pathname: '/', resHeaders: result.resHeaders, @@ -232,20 +295,13 @@ describe('HttpsPlugin Integration tests', () => { component: plugin.component, }; - assert.strictEqual(spans.length, 1); + assert.strictEqual(spans.length, 2); assert.strictEqual(span.name, 'HTTP GET'); - - try { - assertSpan(span, SpanKind.CLIENT, validations); - } catch (error) { - // temporary redirect is also correct - validations.httpStatusCode = 307; - assertSpan(span, SpanKind.CLIENT, validations); - } + assertSpan(span, SpanKind.CLIENT, validations); }); for (const headers of [ - { Expect: '100-continue', 'user-agent': 'https-plugin-test' }, - { 'user-agent': 'https-plugin-test' }, + { Expect: '100-continue', 'user-agent': 'http-plugin-test' }, + { 'user-agent': 'http-plugin-test' }, ]) { it(`should create a span for GET requests and add propagation when using the following signature: get(url, options, callback) and following headers: ${JSON.stringify( headers @@ -263,7 +319,7 @@ describe('HttpsPlugin Integration tests', () => { assert.strictEqual(spans.length, 0); const options = { headers }; const req = https.get( - `${protocol}://google.fr/`, + `${protocol}://localhost:${mockServerPort}/`, options, (resp: http.IncomingMessage) => { const res = (resp as unknown) as http.IncomingMessage & { @@ -275,7 +331,7 @@ describe('HttpsPlugin Integration tests', () => { }); resp.on('end', () => { validations = { - hostname: 'google.fr', + hostname: 'localhost', httpStatusCode: 301, httpMethod: 'GET', pathname: '/', @@ -292,8 +348,10 @@ describe('HttpsPlugin Integration tests', () => { req.on('close', () => { const spans = memoryExporter.getFinishedSpans(); - assert.strictEqual(spans.length, 1); - assert.strictEqual(spans[0].name, 'HTTP GET'); + const span = spans.find(s => s.kind === SpanKind.CLIENT); + assert.ok(span); + assert.strictEqual(spans.length, 2); + assert.strictEqual(span.name, 'HTTP GET'); assert.ok(data); assert.ok(validations.reqHeaders[DummyPropagation.TRACE_CONTEXT_KEY]); assert.ok(validations.reqHeaders[DummyPropagation.SPAN_CONTEXT_KEY]); From a5ca32b8216e627c8c11d6099c7cfe5b68f104ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerhard=20St=C3=B6bich?= Date: Mon, 11 Jan 2021 20:37:26 +0100 Subject: [PATCH 2/4] chore: improve dev setup for windows (#1790) Co-authored-by: Daniel Dyla --- .gitattributes | 2 +- package.json | 2 +- packages/opentelemetry-resource-detector-gcp/tsconfig.json | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index 7d65e84970..0113e927b8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -30,7 +30,7 @@ LICENSE* text ## Non-text documentation *.html text diff=html *.pdf binary -*.json text +*.json text eol=lf *.rtf binary ## Git Properties diff --git a/package.json b/package.json index 986712b69c..504c0c6417 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "lerna-changelog": "1.0.1", "markdownlint-cli": "0.25.0", "typescript": "3.9.7", - "update-ts-references": "^1.3.0" + "update-ts-references": "2.0.0" }, "husky": { "hooks": { diff --git a/packages/opentelemetry-resource-detector-gcp/tsconfig.json b/packages/opentelemetry-resource-detector-gcp/tsconfig.json index 6549996003..954354a3a0 100644 --- a/packages/opentelemetry-resource-detector-gcp/tsconfig.json +++ b/packages/opentelemetry-resource-detector-gcp/tsconfig.json @@ -9,6 +9,9 @@ "test/**/*.ts" ], "references": [ + { + "path": "../opentelemetry-api" + }, { "path": "../opentelemetry-core" }, From e25909df40c7730faed5fa17b5588b64c557f25c Mon Sep 17 00:00:00 2001 From: Aman Brar Date: Mon, 11 Jan 2021 15:34:14 -0500 Subject: [PATCH 3/4] Add CodeQL security scans (#1785) --- .github/workflows/codeql-analysis.yml | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000000..10ad648c67 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,35 @@ +name: "CodeQL Analysis" + +on: + workflow_dispatch: + schedule: + # ┌───────────── minute (0 - 59) + # │ ┌───────────── hour (0 - 23) + # │ │ ┌───────────── day of the month (1 - 31) + # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) + # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) + # │ │ │ │ │ + # │ │ │ │ │ + # │ │ │ │ │ + # * * * * * + - cron: '30 1 * * *' + +jobs: + CodeQL-Build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: javascript + + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 From 4ab9465fd5368f199a846a22d443b4fbc99409b4 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Mon, 11 Jan 2021 22:03:22 +0100 Subject: [PATCH 4/4] chore(deps): pin dependencies (#1783) --- packages/opentelemetry-instrumentation-grpc/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/opentelemetry-instrumentation-grpc/package.json b/packages/opentelemetry-instrumentation-grpc/package.json index 1be36e2fb7..a39b68cf5c 100644 --- a/packages/opentelemetry-instrumentation-grpc/package.json +++ b/packages/opentelemetry-instrumentation-grpc/package.json @@ -41,8 +41,8 @@ "access": "public" }, "devDependencies": { - "@grpc/grpc-js": "^1.2.2", - "@grpc/proto-loader": "^0.5.5", + "@grpc/grpc-js": "1.2.3", + "@grpc/proto-loader": "0.5.5", "@opentelemetry/context-async-hooks": "^0.14.0", "@opentelemetry/context-base": "^0.14.0", "@opentelemetry/core": "^0.14.0",