Skip to content

Commit

Permalink
test: allow FakeAgent to respond to remote config requests
Browse files Browse the repository at this point in the history
  • Loading branch information
watson committed Aug 27, 2024
1 parent 6fabbd0 commit c7f0626
Showing 1 changed file with 95 additions and 0 deletions.
95 changes: 95 additions & 0 deletions integration-tests/helpers.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use strict'

const { promisify } = require('util')
const { createHash } = require('crypto')
const uuid = require('crypto-randomuuid')
const express = require('express')
const bodyParser = require('body-parser')
const msgpack = require('msgpack-lite')
Expand All @@ -24,6 +26,7 @@ class FakeAgent extends EventEmitter {
constructor (port = 0) {
super()
this.port = port
this._rc_files = []
}

async start () {
Expand All @@ -38,6 +41,69 @@ class FakeAgent extends EventEmitter {
payload: msgpack.decode(req.body, { codec })
})
})
app.post('/v0.7/config', (req, res) => {
const buffers = []
req.on('data', buffers.push.bind(buffers))
req.on('end', () => {
const { products } = JSON.parse(Buffer.concat(buffers).toString()).client

const expires = (new Date(Date.now() + 1000 * 60 * 60 * 24)).toISOString() // in 24 hours
const clientID = uuid() // TODO: What is this? It isn't the runtime-id

// Currently, only `opaque_backend_state` and `targets` are used by dd-trace-js in the object below
const targets = {
signatures: [],
signed: {
_type: 'targets',
custom: {
agent_refresh_interval: 5,
opaque_backend_state: ''
},
expires,
spec_version: '1.0.0',
targets: {},
version: 12345
}
}
const opaqueBackendState = {
version: 2,
state: { file_hashes: { key: [] } }
}
const targetFiles = []
const clientConfigs = []

const files = this._rc_files.filter(({ product }) => products.includes(product))

for (const { orgId, product, id, name, config } of files) {
const path = `datadog/${orgId}/${product}/${id}/${name}`
const fileDigest = createHash('sha256').update(config).digest()

opaqueBackendState.state.file_hashes.key.push(fileDigest.toString('base64'))

targets.signed.targets[path] = {
custom: {
c: [clientID],
'tracer-predicates': { tracer_predicates_v1: [{ clientID }] },
v: 20
},
hashes: { sha256: fileDigest.toString('hex') },
length: config.length
}

targetFiles.push({ path, raw: base64(config) })
clientConfigs.push(path)
}

targets.signed.custom.opaque_backend_state = base64(opaqueBackendState)

res.send(JSON.stringify({
roots: [], // Not used by dd-trace-js currently
targets: base64(targets),
target_files: targetFiles,
client_configs: clientConfigs
}))
})
})
app.post('/profiling/v1/input', upload.any(), (req, res) => {
res.status(200).send()
this.emit('message', {
Expand Down Expand Up @@ -75,6 +141,30 @@ class FakeAgent extends EventEmitter {
})
}

/**
* Remove any existing config added by calls to FakeAgent#addRemoteConfig.
*/
resetRemoteConfig () {
this._rc_files = []
}

/**
* Add a config object to be returned by the fake Remote Config endpoint.
* @param {Object} config - Object containing the Remote Config "file" and metadata
* @param {number} [config.orgId=2] - The Datadog organization ID
* @param {string} config.product - The Remote Config product name
* @param {string} config.id - The Remote Config config ID
* @param {string} [config.name] - The Remote Config "name". Defaults to the sha256 hash of `config.id`
* @param {Object} config.config - The Remote Config "file" object
*/
addRemoteConfig (config) {
config.orgId = config.orgId ?? 2
config.name = config.name ?? createHash('sha256').update(config.id).digest('hex')
config.config = JSON.stringify(config.config)

this._rc_files.push(config)
}

// **resolveAtFirstSuccess** - specific use case for Next.js (or any other future libraries)
// where multiple payloads are generated, and only one is expected to have the proper span (ie next.request),
// but it't not guaranteed to be the last one (so, expectedMessageCount would not be helpful).
Expand Down Expand Up @@ -486,6 +576,11 @@ function sandboxCwd () {
return sandbox.folder
}

function base64 (strOrObj) {
const str = typeof strOrObj === 'string' ? strOrObj : JSON.stringify(strOrObj)
return Buffer.from(str).toString('base64')
}

module.exports = {
FakeAgent,
spawnProc,
Expand Down

0 comments on commit c7f0626

Please sign in to comment.