Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add script to test live API integration #128

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
.DS_Store

# Logs
logs
*.log

# IDE
.idea
.vscode

# Runtime data
pids
Expand Down Expand Up @@ -39,6 +42,7 @@ package-lock.json

# Users Environment Variables
.lock-wscript
.env

# Scratch working files
scratch.*
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
"scripts": {
"prepack": "npm run clean && npm run build-types",
"test": "mocha --reporter spec",
"check-integration": "node test-other/integration_check.js",
"check-codestyle": "npx eslint .",
"check-text": "test/lint_text.sh",
"check-text": "test-other/lint_text.sh",
"build-types": "tsc --build",
"check-types": "tsc --noEmit --strict test/types_check.ts",
"check-types": "tsc --noEmit --strict test-other/types_check.ts",
"clean": "tsc --build --clean"
},
"keywords": [
Expand Down
137 changes: 137 additions & 0 deletions test-other/integration_check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/**
* A basic test of our complete integration with Datadog. This check sends some
* metrics, then queries to make sure they actually got ingested correctly by
* Datadog and will show up as expected.
*/

'use strict';

const { client, v1 } = require('@datadog/datadog-api-client');
const datadogMetrics = require('..');

function floorTo(value, points) {
const factor = 10 ** points;
return Math.round(value * factor) / factor;
}

// Remove when upgrading to Node.js 16; this is built-in (node:times/promises).
function sleep(milliseconds) {
return new Promise(r => setTimeout(r, milliseconds));
}

// Make timestamps round seconds for ease of comparison.
const NOW = floorTo(Date.now(), -3);
const MINUTE = 60 * 1000;

// How long to keep querying for the metric before giving up.
const MAX_WAIT_TIME = 2.5 * MINUTE;
// How long to wait between checks.
const CHECK_INTERVAL_SECONDS = 15;

const testPoints = [
[NOW - 60 * 1000, floorTo(10 * Math.random(), 1)],
[NOW - 30 * 1000, floorTo(10 * Math.random(), 1)],
];

const testMetrics = [
{
type: 'gauge',
name: 'node.datadog.metrics.test.gauge',
tags: ['test-tag-1'],
},
{
type: 'distribution',
name: 'node.datadog.metrics.test.dist',
tags: ['test-tag-2'],
},
];

async function main() {
datadogMetrics.init({ flushIntervalSeconds: 0 });

for (const metric of testMetrics) {
await sendMetric(metric);
}

await sleep(5000);

for (const metric of testMetrics) {
const result = await waitForSentMetric(metric);

if (!result) {
process.exitCode = 1;
}
}
}

async function sendMetric(metric) {
console.log(`Sending random points for ${metric.type} "${metric.name}"`);

for (const [timestamp, value] of testPoints) {
datadogMetrics[metric.type](metric.name, value, metric.tags, timestamp);
await new Promise((resolve, reject) => {
datadogMetrics.flush(resolve, reject);
});
}
}

async function queryMetric(metric) {
const configuration = client.createConfiguration({
authMethods: {
apiKeyAuth: process.env.DATADOG_API_KEY,
appKeyAuth: process.env.DATADOG_APP_KEY,
},
});
configuration.setServerVariables({ site: process.env.DATADOG_API_HOST });
const metricsApi = new v1.MetricsApi(configuration);

// NOTE: Query timestamps are seconds, but result points are milliseconds.
const data = await metricsApi.queryMetrics({
from: Math.floor((NOW - 5 * MINUTE) / 1000),
to: Math.ceil(Date.now() / 1000),
query: `${metric.name}{${metric.tags[0]}}`,
});

return data.series && data.series[0];
}

async function waitForSentMetric(metric) {
const endTime = Date.now() + MAX_WAIT_TIME;
while (Date.now() < endTime) {
console.log(`Querying Datadog for sent points in ${metric.type} "${metric.name}"...`);
const series = await queryMetric(metric);

if (series) {
const found = testPoints.every(([timestamp, value]) => {
return series.pointlist.some(([remoteTimestamp, remoteValue]) => {
// Datadog may round values differently or place them into
// time intervals based on the metric's configuration. Look
// for timestamp/value combinations that are close enough.
return (
Math.abs(remoteTimestamp - timestamp) < 10000 &&
Math.abs(remoteValue - value) < 0.1
);
});
});

if (found) {
console.log('✔︎ Found sent points! Test passed.');
return true;
} else {
console.log(' Found series, but with no matching points.');
console.log(` Looking for: ${JSON.stringify(testPoints)}`);
console.log(' Found:', JSON.stringify(series, null, 2));
}
}

console.log(` Nothing found, waiting ${CHECK_INTERVAL_SECONDS}s before trying again.`);
await sleep(CHECK_INTERVAL_SECONDS * 1000);
}

console.log('✘ Nothing found and gave up waiting. Test failed!');
return false;
}

if (require.main === module) {
main().catch(error => console.error(error));
}
File renamed without changes.
File renamed without changes.