-
Notifications
You must be signed in to change notification settings - Fork 513
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: added base tests for Koa core and Koa router
- Loading branch information
1 parent
1b35f8b
commit d8f72f4
Showing
2 changed files
with
342 additions
and
0 deletions.
There are no files selected for viewing
149 changes: 149 additions & 0 deletions
149
plugins/node/opentelemetry-plugin-koa/test/koa-router.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
/*! | ||
* Copyright 2020, OpenTelemetry Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
import { context } from '@opentelemetry/api'; | ||
import { NoopLogger } from '@opentelemetry/core'; | ||
import { NodeTracerProvider } from '@opentelemetry/node'; | ||
import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; | ||
import { | ||
InMemorySpanExporter, | ||
SimpleSpanProcessor, | ||
} from '@opentelemetry/tracing'; | ||
import * as assert from 'assert'; | ||
import * as koa from 'koa'; | ||
import * as KoaRouter from '@koa/router'; | ||
// const router = require('@koa/router')(); | ||
|
||
import * as http from 'http'; | ||
import { AddressInfo } from 'net'; | ||
import { plugin } from '../src'; | ||
import { | ||
AttributeNames | ||
} from '../src/types'; | ||
|
||
|
||
const httpRequest = { | ||
get: (options: http.ClientRequestArgs | string) => { | ||
return new Promise((resolve, reject) => { | ||
return http.get(options, resp => { | ||
let data = ''; | ||
resp.on('data', chunk => { | ||
data += chunk; | ||
}); | ||
resp.on('end', () => { | ||
resolve(data); | ||
}); | ||
resp.on('error', err => { | ||
reject(err); | ||
}); | ||
}); | ||
}); | ||
}, | ||
}; | ||
|
||
|
||
describe('Koa Plugin', () => { | ||
const logger = new NoopLogger(); | ||
const provider = new NodeTracerProvider(); | ||
const memoryExporter = new InMemorySpanExporter(); | ||
const spanProcessor = new SimpleSpanProcessor(memoryExporter); | ||
provider.addSpanProcessor(spanProcessor); | ||
const tracer = provider.getTracer('default'); | ||
let contextManager: AsyncHooksContextManager; | ||
|
||
before(() => { | ||
plugin.enable(koa, provider, logger); | ||
}); | ||
|
||
beforeEach(() => { | ||
contextManager = new AsyncHooksContextManager(); | ||
context.setGlobalContextManager(contextManager.enable()); | ||
}); | ||
|
||
afterEach(() => { | ||
memoryExporter.reset(); | ||
context.disable(); | ||
}); | ||
|
||
describe('Instrumenting @koa/router calls', () => { | ||
it('should create a child span for middlewares', async () => { | ||
const rootSpan = tracer.startSpan('rootSpan'); | ||
const app = new koa(); | ||
app.use((ctx, next) => tracer.withSpan(rootSpan, next)); | ||
|
||
const router = new KoaRouter(); | ||
router.get('/', (ctx) => { | ||
ctx.body = "list" | ||
}); | ||
router.get('/post/new', (ctx) => { | ||
ctx.body = "add" | ||
}); | ||
router.get('/post/:id', (ctx) => { | ||
const id = ctx.params.id; | ||
console.log("id is: " + id); | ||
}); | ||
|
||
router.post('/post', async (ctx) => { | ||
const post = ctx.body; | ||
post.created_at = new Date(); | ||
ctx.redirect('/'); | ||
}); | ||
|
||
app.use(router.routes()); | ||
|
||
const server = http.createServer(app.callback()); | ||
await new Promise(resolve => server.listen(0, resolve)); | ||
const port = (server.address() as AddressInfo).port; | ||
assert.strictEqual(memoryExporter.getFinishedSpans().length, 0); | ||
|
||
|
||
await tracer.withSpan(rootSpan, async () => { | ||
await httpRequest.get(`http://localhost:${port}/post/0`); | ||
rootSpan.end(); | ||
|
||
|
||
const requestHandlerSpan = memoryExporter | ||
.getFinishedSpans() | ||
.find(span => span.name.includes('/post/:id')); | ||
assert.notStrictEqual(requestHandlerSpan, undefined); | ||
assert.strictEqual( | ||
requestHandlerSpan?.attributes[AttributeNames.COMPONENT], | ||
'koa' | ||
); | ||
|
||
assert.strictEqual( | ||
requestHandlerSpan?.attributes[AttributeNames.KOA_TYPE], | ||
'middleware' | ||
); | ||
|
||
assert.strictEqual( | ||
requestHandlerSpan?.attributes[AttributeNames.PATH], | ||
'/post/:id' | ||
); | ||
|
||
let exportedRootSpan = memoryExporter | ||
.getFinishedSpans() | ||
.find(span => span.name === 'rootSpan'); | ||
assert.notStrictEqual(exportedRootSpan, undefined); | ||
}); | ||
server.close(); | ||
}); | ||
|
||
|
||
|
||
}); | ||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
/*! | ||
* Copyright 2020, OpenTelemetry Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
import { context } from '@opentelemetry/api'; | ||
import { NoopLogger } from '@opentelemetry/core'; | ||
import { NodeTracerProvider } from '@opentelemetry/node'; | ||
import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; | ||
import { | ||
InMemorySpanExporter, | ||
SimpleSpanProcessor, | ||
} from '@opentelemetry/tracing'; | ||
import * as assert from 'assert'; | ||
import * as koa from 'koa'; | ||
import * as http from 'http'; | ||
import { AddressInfo } from 'net'; | ||
import { plugin } from '../src'; | ||
import { | ||
AttributeNames | ||
} from '../src/types'; | ||
|
||
|
||
const httpRequest = { | ||
get: (options: http.ClientRequestArgs | string) => { | ||
return new Promise((resolve, reject) => { | ||
return http.get(options, resp => { | ||
let data = ''; | ||
resp.on('data', chunk => { | ||
data += chunk; | ||
}); | ||
resp.on('end', () => { | ||
resolve(data); | ||
}); | ||
resp.on('error', err => { | ||
reject(err); | ||
}); | ||
}); | ||
}); | ||
}, | ||
}; | ||
|
||
|
||
describe('Koa Plugin', () => { | ||
const logger = new NoopLogger(); | ||
const provider = new NodeTracerProvider(); | ||
const memoryExporter = new InMemorySpanExporter(); | ||
const spanProcessor = new SimpleSpanProcessor(memoryExporter); | ||
provider.addSpanProcessor(spanProcessor); | ||
const tracer = provider.getTracer('default'); | ||
let contextManager: AsyncHooksContextManager; | ||
|
||
before(() => { | ||
plugin.enable(koa, provider, logger); | ||
}); | ||
|
||
beforeEach(() => { | ||
contextManager = new AsyncHooksContextManager(); | ||
context.setGlobalContextManager(contextManager.enable()); | ||
}); | ||
|
||
afterEach(() => { | ||
memoryExporter.reset(); | ||
context.disable(); | ||
}); | ||
|
||
describe('Instrumenting core middleware calls', () => { | ||
it('should create a child span for middlewares', async () => { | ||
const rootSpan = tracer.startSpan('rootSpan'); | ||
const app = new koa(); | ||
app.use((ctx, next) => tracer.withSpan(rootSpan, next)); | ||
app.use(function customMiddleware(ctx, next) { | ||
for (let i = 0; i < 1000000; i++) { | ||
continue; | ||
} | ||
return next(); | ||
}); | ||
app.use(function simpleResponse(ctx, next) { | ||
ctx.body = 'test'; | ||
return next(); | ||
}); | ||
|
||
app.use(function (ctx, next) { | ||
ctx.body = 'anonymous'; | ||
return next(); | ||
}); | ||
|
||
const server = http.createServer(app.callback()); | ||
await new Promise(resolve => server.listen(0, resolve)); | ||
const port = (server.address() as AddressInfo).port; | ||
assert.strictEqual(memoryExporter.getFinishedSpans().length, 0); | ||
|
||
|
||
await tracer.withSpan(rootSpan, async () => { | ||
await httpRequest.get(`http://localhost:${port}`); | ||
rootSpan.end(); | ||
assert.notStrictEqual( | ||
memoryExporter | ||
.getFinishedSpans() | ||
.find(span => span.name.includes('customMiddleware')), | ||
undefined | ||
); | ||
|
||
const simpleResponseSpan = memoryExporter | ||
.getFinishedSpans() | ||
.find(span => span.name.includes('simpleResponse')); | ||
assert.notStrictEqual(simpleResponseSpan, undefined); | ||
|
||
const requestHandlerSpan = memoryExporter | ||
.getFinishedSpans() | ||
.find(span => span.name.includes('middleware')); | ||
assert.notStrictEqual(requestHandlerSpan, undefined); | ||
assert.strictEqual( | ||
requestHandlerSpan?.attributes[AttributeNames.COMPONENT], | ||
'koa' | ||
); | ||
|
||
assert.strictEqual( | ||
requestHandlerSpan?.attributes[AttributeNames.KOA_TYPE], | ||
'middleware' | ||
); | ||
let exportedRootSpan = memoryExporter | ||
.getFinishedSpans() | ||
.find(span => span.name === 'rootSpan'); | ||
assert.notStrictEqual(exportedRootSpan, undefined); | ||
}); | ||
server.close(); | ||
}); | ||
|
||
it('should not create span if there is no parent span', async () => { | ||
const app = new koa(); | ||
app.use(function customMiddleware(ctx, next) { | ||
for (let i = 0; i < 1000000; i++) { | ||
continue; | ||
} | ||
return next(); | ||
}); | ||
app.use(function response(ctx, next) { | ||
ctx.status = 200; | ||
ctx.body = 'test'; | ||
return next(); | ||
}); | ||
|
||
const server = http.createServer(app.callback()); | ||
await new Promise(resolve => server.listen(0, resolve)); | ||
const port = (server.address() as AddressInfo).port; | ||
assert.strictEqual(memoryExporter.getFinishedSpans().length, 0); | ||
const res = await httpRequest.get(`http://localhost:${port}`); | ||
assert.strictEqual(memoryExporter.getFinishedSpans().length, 0); | ||
assert.strictEqual(res, 'test'); | ||
server.close(); | ||
}); | ||
|
||
}); | ||
|
||
|
||
describe('Disabling plugin', () => { | ||
it('should not create new spans', async () => { | ||
plugin.disable(); | ||
const rootSpan = tracer.startSpan('rootSpan'); | ||
const app = new koa(); | ||
app.use(function customMiddleware(ctx, next) { | ||
for (let i = 0; i < 1000; i++) { | ||
continue; | ||
} | ||
return next(); | ||
}); | ||
const server = http.createServer(app.callback()); | ||
await new Promise(resolve => server.listen(0, resolve)); | ||
const port = (server.address() as AddressInfo).port; | ||
assert.strictEqual(memoryExporter.getFinishedSpans().length, 0); | ||
await tracer.withSpan(rootSpan, async () => { | ||
await httpRequest.get(`http://localhost:${port}`); | ||
rootSpan.end(); | ||
assert.deepEqual(memoryExporter.getFinishedSpans().length, 1); | ||
assert.notStrictEqual(memoryExporter.getFinishedSpans()[0], undefined); | ||
}); | ||
server.close(); | ||
}); | ||
}); | ||
}); | ||
|