Skip to content

Commit 19e9d9d

Browse files
committed
test: re-enable schema tests for the v2 api (elastic#585)
1 parent 5db63c8 commit 19e9d9d

File tree

10 files changed

+406
-256
lines changed

10 files changed

+406
-256
lines changed

lib/instrumentation/span.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ Span.prototype._encode = function (cb) {
149149
var payload = {
150150
id: self.id,
151151
transaction_id: self.transaction.id,
152+
parent_id: self.transaction.id,
152153
trace_id: self.transaction.traceId,
153154
timestamp: self.transaction.timestamp,
154155
name: self.name,

test/instrumentation/span.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,10 @@ test('#_encode() - ended unnamed', function myTest1 (t) {
109109
span.end()
110110
span._encode(function (err, payload) {
111111
t.error(err)
112-
t.deepEqual(Object.keys(payload), ['id', 'transaction_id', 'trace_id', 'timestamp', 'name', 'type', 'start', 'duration', 'stacktrace'])
112+
t.deepEqual(Object.keys(payload), ['id', 'transaction_id', 'parent_id', 'trace_id', 'timestamp', 'name', 'type', 'start', 'duration', 'stacktrace'])
113113
t.ok(/^[\da-f]{16}$/.test(payload.id))
114114
t.ok(/^[\da-f]{16}$/.test(payload.transaction_id))
115+
t.ok(/^[\da-f]{16}$/.test(payload.parent_id))
115116
t.ok(/^[\da-f]{32}$/.test(payload.trace_id))
116117
t.equal(payload.transaction_id, trans.id)
117118
t.equal(payload.timestamp, trans.timestamp)
@@ -132,9 +133,10 @@ test('#_encode() - ended named', function myTest2 (t) {
132133
span.end()
133134
span._encode(function (err, payload) {
134135
t.error(err)
135-
t.deepEqual(Object.keys(payload), ['id', 'transaction_id', 'trace_id', 'timestamp', 'name', 'type', 'start', 'duration', 'stacktrace'])
136+
t.deepEqual(Object.keys(payload), ['id', 'transaction_id', 'parent_id', 'trace_id', 'timestamp', 'name', 'type', 'start', 'duration', 'stacktrace'])
136137
t.ok(/^[\da-f]{16}$/.test(payload.id))
137138
t.ok(/^[\da-f]{16}$/.test(payload.transaction_id))
139+
t.ok(/^[\da-f]{16}$/.test(payload.parent_id))
138140
t.ok(/^[\da-f]{32}$/.test(payload.trace_id))
139141
t.equal(payload.transaction_id, trans.id)
140142
t.equal(payload.timestamp, trans.timestamp)
@@ -157,9 +159,10 @@ test('#_encode() - disabled stack traces', function (t) {
157159
span.end()
158160
span._encode(function (err, payload) {
159161
t.error(err)
160-
t.deepEqual(Object.keys(payload), ['id', 'transaction_id', 'trace_id', 'timestamp', 'name', 'type', 'start', 'duration'])
162+
t.deepEqual(Object.keys(payload), ['id', 'transaction_id', 'parent_id', 'trace_id', 'timestamp', 'name', 'type', 'start', 'duration'])
161163
t.ok(/^[\da-f]{16}$/.test(payload.id))
162164
t.ok(/^[\da-f]{16}$/.test(payload.transaction_id))
165+
t.ok(/^[\da-f]{16}$/.test(payload.parent_id))
163166
t.ok(/^[\da-f]{32}$/.test(payload.trace_id))
164167
t.equal(payload.transaction_id, trans.id)
165168
t.equal(payload.timestamp, trans.timestamp)

test/integration/api-schema/_utils.js

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict'
22

33
const exec = require('child_process').exec
4+
const fs = require('fs')
45
const tmpdir = require('os').tmpdir
56
const join = require('path').join
67

@@ -10,21 +11,33 @@ const thunky = require('thunky')
1011

1112
const schemaDir = thunky(function (cb) {
1213
const dir = join(tmpdir(), '.schemacache')
13-
const script = join(__dirname, 'download-json-schemas.sh')
14-
const cmd = `"${script}" "${dir}"`
15-
console.log('downloading schemas from GitHub to %s...', dir)
16-
exec(cmd, function (err) {
17-
if (err) return cb(err)
18-
cb(null, dir)
14+
fs.stat(dir, function (err) {
15+
if (!err) return cb(null, dir)
16+
17+
const script = join(__dirname, 'download-json-schemas.sh')
18+
const cmd = `"${script}" "${dir}"`
19+
console.log('downloading schemas from GitHub to %s...', dir)
20+
exec(cmd, function (err) {
21+
if (err) return cb(err)
22+
cb(null, dir)
23+
})
1924
})
2025
})
2126

22-
exports.transactionsValidator = thunky(function (cb) {
23-
loadSchema(join('transactions', 'v1_transaction.json'), cb)
27+
exports.metadataValidator = thunky(function (cb) {
28+
loadSchema('metadata.json', cb)
29+
})
30+
31+
exports.transactionValidator = thunky(function (cb) {
32+
loadSchema(join('transactions', 'v2_transaction.json'), cb)
33+
})
34+
35+
exports.spanValidator = thunky(function (cb) {
36+
loadSchema(join('spans', 'v2_span.json'), cb)
2437
})
2538

26-
exports.errorsValidator = thunky(function (cb) {
27-
loadSchema(join('errors', 'v1_error.json'), cb)
39+
exports.errorValidator = thunky(function (cb) {
40+
loadSchema(join('errors', 'v2_error.json'), cb)
2841
})
2942

3043
function loadSchema (relativePath, cb) {

test/integration/api-schema/basic.js

Lines changed: 162 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -5,80 +5,148 @@ if (require('os').platform() === 'win32') {
55
process.exit()
66
}
77

8-
const getPort = require('get-port')
8+
const http = require('http')
9+
const zlib = require('zlib')
10+
11+
const afterAll = require('after-all-results')
12+
const ndjson = require('ndjson')
13+
const test = require('tape')
14+
15+
const utils = require('./_utils')
16+
const Agent = require('../../_agent')
17+
18+
const next = afterAll(function (err, validators) {
19+
if (err) throw err
20+
21+
const [validateMetadata, validateTransaction, validateSpan, validateError] = validators
22+
23+
test('metadata schema failure', function (t) {
24+
t.equal(validateMetadata({}), false)
25+
t.deepEqual(validateMetadata.errors, [
26+
{ field: 'data.service', message: 'is required', value: {}, type: [ 'object' ], schemaPath: [] }
27+
])
28+
t.equal(validateMetadata({ service: {} }), false)
29+
t.deepEqual(validateMetadata.errors, [
30+
{ field: 'data.service.agent', message: 'is required', value: {}, type: 'object', schemaPath: [ 'properties', 'service' ] },
31+
{ field: 'data.service.name', message: 'is required', value: {}, type: 'object', schemaPath: [ 'properties', 'service' ] }
32+
])
33+
t.end()
34+
})
935

10-
getPort().then(function (port) {
11-
const agent = require('../../../').start({
12-
serviceName: 'test',
13-
serverUrl: 'http://localhost:' + port,
14-
captureExceptions: false
36+
test('transaction schema failure', function (t) {
37+
t.equal(validateTransaction({}), false)
38+
t.deepEqual(validateTransaction.errors, [
39+
{ field: 'data.duration', message: 'is required', value: {}, type: 'object', schemaPath: [ 'allOf', 0 ] },
40+
{ field: 'data.type', message: 'is required', value: {}, type: 'object', schemaPath: [ 'allOf', 0 ] },
41+
{ field: 'data.id', message: 'is required', value: {}, type: undefined, schemaPath: [ 'allOf', 1 ] },
42+
{ field: 'data.trace_id', message: 'is required', value: {}, type: undefined, schemaPath: [ 'allOf', 1 ] },
43+
{ field: 'data.span_count', message: 'is required', value: {}, type: undefined, schemaPath: [ 'allOf', 1 ] }
44+
])
45+
t.end()
1546
})
1647

17-
const http = require('http')
18-
const zlib = require('zlib')
19-
const test = require('tape')
20-
const utils = require('./_utils')
21-
22-
test('transactions schema failure', function (t) {
23-
utils.transactionsValidator(function (err, validate) {
24-
t.error(err)
25-
t.notOk(validate({}))
26-
t.deepEqual(validate.errors, [
27-
{ field: 'data.service', message: 'is required', value: {}, type: 'object', schemaPath: [] },
28-
{ field: 'data.transactions', message: 'is required', value: {}, type: 'object', schemaPath: [] }
29-
])
30-
t.end()
31-
})
48+
test('span schema failure', function (t) {
49+
t.equal(validateSpan({}), false)
50+
t.deepEqual(validateSpan.errors, [
51+
{ field: 'data.duration', message: 'is required', value: {}, type: 'object', schemaPath: [] },
52+
{ field: 'data.name', message: 'is required', value: {}, type: 'object', schemaPath: [] },
53+
{ field: 'data.start', message: 'is required', value: {}, type: 'object', schemaPath: [] },
54+
{ field: 'data.type', message: 'is required', value: {}, type: 'object', schemaPath: [] }
55+
])
56+
t.end()
3257
})
3358

34-
test('errors schema failure', function (t) {
35-
utils.errorsValidator(function (err, validate) {
36-
t.error(err)
37-
t.notOk(validate({}))
38-
t.deepEqual(validate.errors, [
39-
{ field: 'data.service', message: 'is required', value: {}, type: 'object', schemaPath: [] },
40-
{ field: 'data.errors', message: 'is required', value: {}, type: 'object', schemaPath: [] }
41-
])
42-
t.end()
43-
})
59+
test('error schema failure', function (t) {
60+
t.equal(validateError({}), false)
61+
t.deepEqual(validateError.errors, [
62+
{ field: 'data', message: 'no schemas match', value: {}, type: 'object', schemaPath: [ 'allOf', 0 ] }
63+
])
64+
t.equal(validateError({ exception: {} }), false)
65+
t.deepEqual(validateError.errors, [
66+
{ field: 'data.exception', message: 'no schemas match', value: {}, type: [ 'object', 'null' ], schemaPath: [ 'allOf', 0, 'properties', 'exception' ] }
67+
])
68+
t.equal(validateError({ log: {} }), false)
69+
t.deepEqual(validateError.errors, [
70+
{ field: 'data.log.message', message: 'is required', value: {}, type: [ 'object', 'null' ], schemaPath: [ 'allOf', 0, 'properties', 'log' ] }
71+
])
72+
t.end()
4473
})
4574

46-
test('POST /transactions', function (t) {
75+
test('metadata + transaction schema', function (t) {
4776
t.plan(7)
4877

49-
utils.transactionsValidator(function (err, validate) {
50-
t.error(err)
78+
let agent
79+
const validators = [validateMetadata, validateTransaction]
80+
81+
const server = http.createServer(function (req, res) {
82+
t.equal(req.method, 'POST', 'server should recieve a POST request')
83+
t.equal(req.url, '/intake/v2/events', 'server should recieve request to correct endpoint')
84+
85+
req
86+
.pipe(zlib.createGunzip())
87+
.pipe(ndjson.parse())
88+
.on('data', function (data) {
89+
const type = Object.keys(data)[0]
90+
const validate = validators.shift()
91+
t.equal(validate(data[type]), true, type + ' should be valid')
92+
t.equal(validate.errors, null, type + ' should not have any validation errors')
93+
})
94+
.on('end', function () {
95+
res.end()
96+
server.close()
97+
agent.destroy()
98+
t.end()
99+
})
100+
})
51101

52-
const server = http.createServer(function (req, res) {
53-
t.equal(req.method, 'POST')
54-
t.equal(req.url, '/v1/transactions')
102+
server.listen(function () {
103+
agent = newAgent(server)
104+
agent.startTransaction('name1', 'type1')
105+
agent.endTransaction()
106+
agent.flush(function (err) {
107+
t.error(err, 'flush should not result in an error')
108+
})
109+
})
110+
})
55111

56-
const buffers = []
57-
const gunzip = zlib.createGunzip()
58-
const unzipped = req.pipe(gunzip)
112+
test('metadata + span schema', function (t) {
113+
t.plan(7)
59114

60-
unzipped.on('data', buffers.push.bind(buffers))
61-
unzipped.on('end', function () {
115+
let agent
116+
const validators = [validateMetadata, validateSpan]
117+
118+
const server = http.createServer(function (req, res) {
119+
t.equal(req.method, 'POST', 'server should recieve a POST request')
120+
t.equal(req.url, '/intake/v2/events', 'server should recieve request to correct endpoint')
121+
122+
req
123+
.pipe(zlib.createGunzip())
124+
.pipe(ndjson.parse())
125+
.on('data', function (data) {
126+
const type = Object.keys(data)[0]
127+
const validate = validators.shift()
128+
t.equal(validate(data[type]), true, type + ' should be valid')
129+
t.equal(validate.errors, null, type + ' should not have any validation errors')
130+
})
131+
.on('end', function () {
62132
res.end()
63133
server.close()
64-
const data = JSON.parse(Buffer.concat(buffers))
65-
t.equal(data.transactions.length, 1, 'expect 1 transaction to be sent')
66-
const valid = validate(data)
67-
t.equal(validate.errors, null, 'should not have any validation errors')
68-
t.equal(valid, true, 'should be valid')
134+
agent.destroy()
135+
t.end()
69136
})
70-
})
137+
})
71138

72-
server.listen(port, function () {
73-
agent.startTransaction('name1', 'type1')
74-
const span = agent.startSpan('name1', 'type1')
75-
span.end()
76-
agent.endTransaction()
139+
server.listen(function () {
140+
agent = newAgent(server)
141+
agent.startTransaction()
142+
const span = agent.startSpan('name1', 'type1')
143+
span.end()
144+
// Collecting the span stack trace is an async process. Wait a little before flushing
145+
setTimeout(function () {
77146
agent.flush(function (err) {
78-
server.close()
79-
t.error(err)
147+
t.error(err, 'flush should not result in an error')
80148
})
81-
})
149+
}, 250)
82150
})
83151
})
84152

@@ -87,41 +155,53 @@ getPort().then(function (port) {
87155
'just a string'
88156
]
89157
errors.forEach(function (error, index) {
90-
test('POST /errors - ' + index, function (t) {
158+
test('metadata + error schema - ' + index, function (t) {
91159
t.plan(7)
92160

93-
utils.errorsValidator(function (err, validate) {
94-
t.error(err)
95-
96-
const server = http.createServer(function (req, res) {
97-
t.equal(req.method, 'POST')
98-
t.equal(req.url, '/v1/errors')
161+
let agent
162+
const validators = [validateMetadata, validateError]
99163

100-
const buffers = []
101-
const gunzip = zlib.createGunzip()
102-
const unzipped = req.pipe(gunzip)
103-
104-
unzipped.on('data', buffers.push.bind(buffers))
105-
unzipped.on('end', function () {
164+
const server = http.createServer(function (req, res) {
165+
t.equal(req.method, 'POST', 'server should recieve a POST request')
166+
t.equal(req.url, '/intake/v2/events', 'server should recieve request to correct endpoint')
167+
168+
req
169+
.pipe(zlib.createGunzip())
170+
.pipe(ndjson.parse())
171+
.on('data', function (data) {
172+
const type = Object.keys(data)[0]
173+
const validate = validators.shift()
174+
t.equal(validate(data[type]), true, type + ' should be valid')
175+
t.equal(validate.errors, null, type + ' should not have any validation errors')
176+
})
177+
.on('end', function () {
106178
res.end()
107179
server.close()
108-
const data = JSON.parse(Buffer.concat(buffers))
109-
t.equal(data.errors.length, 1, 'expect 1 error to be sent')
110-
const valid = validate(data)
111-
t.equal(validate.errors, null, 'should not have any validation errors')
112-
t.equal(valid, true, 'should be valid')
180+
agent.destroy()
181+
t.end()
113182
})
114-
})
183+
})
115184

116-
server.listen(port, function () {
117-
agent.captureError(error, function (err) {
118-
server.close()
119-
t.error(err)
120-
})
185+
server.listen(function () {
186+
agent = newAgent(server)
187+
agent.captureError(error, function (err) {
188+
t.error(err, 'captureError should not result in an error')
121189
})
122190
})
123191
})
124192
})
125-
}, function (err) {
126-
throw err
127193
})
194+
195+
utils.metadataValidator(next())
196+
utils.transactionValidator(next())
197+
utils.spanValidator(next())
198+
utils.errorValidator(next())
199+
200+
function newAgent (server) {
201+
return new Agent().start({
202+
serviceName: 'test',
203+
serverUrl: 'http://localhost:' + server.address().port,
204+
captureExceptions: false,
205+
disableInstrumentations: ['http']
206+
})
207+
}

0 commit comments

Comments
 (0)