From ddb2af6054e46dde75e69e689491d5c0c2c10962 Mon Sep 17 00:00:00 2001 From: Danielle Adams Date: Mon, 27 Apr 2020 08:53:12 -0400 Subject: [PATCH 1/2] add spec support for Node 13 and 14 --- spec/ci/node_13_metrics_spec.rb | 25 +++++++ spec/ci/node_13_spec.rb | 16 +++++ spec/ci/node_14_metrics_spec.rb | 25 +++++++ spec/ci/node_14_spec.rb | 16 +++++ spec/fixtures/repos/node-14-metrics/Procfile | 1 + spec/fixtures/repos/node-14-metrics/index.js | 72 +++++++++++++++++++ .../repos/node-14-metrics/package.json | 11 +++ spec/fixtures/repos/node-14/Procfile | 1 + spec/fixtures/repos/node-14/app.json | 3 + spec/fixtures/repos/node-14/index.js | 46 ++++++++++++ spec/fixtures/repos/node-14/package.json | 21 ++++++ spec/spec_helper.rb | 6 +- 12 files changed, 240 insertions(+), 3 deletions(-) create mode 100644 spec/ci/node_13_metrics_spec.rb create mode 100644 spec/ci/node_13_spec.rb create mode 100644 spec/ci/node_14_metrics_spec.rb create mode 100644 spec/ci/node_14_spec.rb create mode 100644 spec/fixtures/repos/node-14-metrics/Procfile create mode 100755 spec/fixtures/repos/node-14-metrics/index.js create mode 100644 spec/fixtures/repos/node-14-metrics/package.json create mode 100644 spec/fixtures/repos/node-14/Procfile create mode 100644 spec/fixtures/repos/node-14/app.json create mode 100755 spec/fixtures/repos/node-14/index.js create mode 100644 spec/fixtures/repos/node-14/package.json diff --git a/spec/ci/node_13_metrics_spec.rb b/spec/ci/node_13_metrics_spec.rb new file mode 100644 index 000000000..ba09fe7a5 --- /dev/null +++ b/spec/ci/node_13_metrics_spec.rb @@ -0,0 +1,25 @@ +require_relative '../spec_helper' + +describe "Node Metrics for v13.x" do + context "test metrics for Node v13.x app" do + let(:app) { + Hatchet::Runner.new( + "spec/fixtures/repos/node-13-metrics", + config: { + "HEROKU_METRICS_URL" => "http://localhost:3000", + "METRICS_INTERVAL_OVERRIDE" => "10000" + } + ) + } + + it "should deploy" do + app.deploy do |app| + data = successful_json_body(app) + expect(data["gauges"]["node.eventloop.delay.ms.max"]).to be >= 2000 + expect(data["counters"]["node.gc.collections"]).to be >= 0 + expect(data["counters"]["node.gc.young.collections"]).to be >= 0 + expect(data["counters"]["node.gc.old.collections"]).to be >= 0 + end + end + end +end diff --git a/spec/ci/node_13_spec.rb b/spec/ci/node_13_spec.rb new file mode 100644 index 000000000..e367cea08 --- /dev/null +++ b/spec/ci/node_13_spec.rb @@ -0,0 +1,16 @@ +require_relative '../spec_helper' + +describe "Hello World for Node v13.x" do + context "a single-process Node v13.x app" do + let(:app) { + Hatchet::Runner.new("spec/fixtures/repos/node-13") + } + + it "should deploy successfully" do + app.deploy do |app| + expect(successful_body(app).strip).to eq("Hello, world!") + end + end + + end +end diff --git a/spec/ci/node_14_metrics_spec.rb b/spec/ci/node_14_metrics_spec.rb new file mode 100644 index 000000000..3a008d9fe --- /dev/null +++ b/spec/ci/node_14_metrics_spec.rb @@ -0,0 +1,25 @@ +require_relative '../spec_helper' + +describe "Node Metrics for v14.x" do + context "test metrics for Node v14.x app" do + let(:app) { + Hatchet::Runner.new( + "spec/fixtures/repos/node-14-metrics", + config: { + "HEROKU_METRICS_URL" => "http://localhost:3000", + "METRICS_INTERVAL_OVERRIDE" => "10000" + } + ) + } + + it "should deploy" do + app.deploy do |app| + data = successful_json_body(app) + expect(data["gauges"]["node.eventloop.delay.ms.max"]).to be >= 2000 + expect(data["counters"]["node.gc.collections"]).to be >= 0 + expect(data["counters"]["node.gc.young.collections"]).to be >= 0 + expect(data["counters"]["node.gc.old.collections"]).to be >= 0 + end + end + end +end diff --git a/spec/ci/node_14_spec.rb b/spec/ci/node_14_spec.rb new file mode 100644 index 000000000..10188db8f --- /dev/null +++ b/spec/ci/node_14_spec.rb @@ -0,0 +1,16 @@ +require_relative '../spec_helper' + +describe "Hello World for Node v14.x" do + context "a single-process Node v14.x app" do + let(:app) { + Hatchet::Runner.new("spec/fixtures/repos/node-14") + } + + it "should deploy successfully" do + app.deploy do |app| + expect(successful_body(app).strip).to eq("Hello, world!") + end + end + + end +end diff --git a/spec/fixtures/repos/node-14-metrics/Procfile b/spec/fixtures/repos/node-14-metrics/Procfile new file mode 100644 index 000000000..1da0cd6f6 --- /dev/null +++ b/spec/fixtures/repos/node-14-metrics/Procfile @@ -0,0 +1 @@ +web: node index.js diff --git a/spec/fixtures/repos/node-14-metrics/index.js b/spec/fixtures/repos/node-14-metrics/index.js new file mode 100755 index 000000000..eae912a05 --- /dev/null +++ b/spec/fixtures/repos/node-14-metrics/index.js @@ -0,0 +1,72 @@ +#!/usr/bin/env node + +const http = require('http'); +const EventEmitter = require('events'); + +const PORT = process.env.PORT || 5000; +const Events = new EventEmitter(); + +// This will block the event loop for ~lengths of time +function blockCpuFor(ms) { + return new Promise((resolve, reject) => { + setTimeout(() => { + console.log(`blocking the event loop for ${ms}ms`); + let now = new Date().getTime(); + let result = 0 + while(true) { + result += Math.random() * Math.random(); + if (new Date().getTime() > now + ms) + break; + } + resolve(); + }, 100); + }); +} + +function getNextMetricsEvent() { + return new Promise((resolve, reject) => Events.once('metrics', resolve)); +} + +const server = http.createServer((req, res) => { + // wait for the next metrics event + getNextMetricsEvent() + .then(blockCpuFor(2000)) + .then(blockCpuFor(100)) + .then(blockCpuFor(100)) + .then(blockCpuFor(100)) + .then(blockCpuFor(100)) + .then(blockCpuFor(100)) + .then(blockCpuFor(100)) + .then(blockCpuFor(100)) + .then(blockCpuFor(100)) + .then(blockCpuFor(100)) + .then(blockCpuFor(100)) + // gather the next metrics data which should include these pauses + .then(getNextMetricsEvent()) + .then(data => { + res.setHeader('Content-Type', 'application/json'); + res.end(data); + }) + .catch(() => { + res.statusCode = 500; + res.end("Something went wrong"); + }); +}); + +server.listen(PORT, () => console.log(`Listening on ${PORT}`)); + +// Create a second server that intercepts the HTTP requests +// sent by the metrics plugin +const metricsListener = http.createServer((req, res) => { + if (req.method == 'POST') { + let body = ''; + req.on('data', (data) => body += data); + req.on('end', () => { + res.statusCode = 200; + res.end(); + Events.emit('metrics', body) + }); + } +}); + +metricsListener.listen(3000, () => console.log('Listening for metrics on 3000')); diff --git a/spec/fixtures/repos/node-14-metrics/package.json b/spec/fixtures/repos/node-14-metrics/package.json new file mode 100644 index 000000000..c7518c283 --- /dev/null +++ b/spec/fixtures/repos/node-14-metrics/package.json @@ -0,0 +1,11 @@ +{ + "name": "node-metrics-test-app", + "version": "1.0.0", + "engines": { + "node": "14.x" + }, + "main": "index.js", + "license": "MIT", + "devDependencies": {}, + "dependencies": {} +} diff --git a/spec/fixtures/repos/node-14/Procfile b/spec/fixtures/repos/node-14/Procfile new file mode 100644 index 000000000..1da0cd6f6 --- /dev/null +++ b/spec/fixtures/repos/node-14/Procfile @@ -0,0 +1 @@ +web: node index.js diff --git a/spec/fixtures/repos/node-14/app.json b/spec/fixtures/repos/node-14/app.json new file mode 100644 index 000000000..63b5c96f2 --- /dev/null +++ b/spec/fixtures/repos/node-14/app.json @@ -0,0 +1,3 @@ +{ + "name": "hello-world" +} diff --git a/spec/fixtures/repos/node-14/index.js b/spec/fixtures/repos/node-14/index.js new file mode 100755 index 000000000..39a499a1b --- /dev/null +++ b/spec/fixtures/repos/node-14/index.js @@ -0,0 +1,46 @@ +#!/usr/bin/env node + +const http = require('http'); +const crypto = require('crypto'); + +const PORT = process.env.PORT || 5000; + +// This will block the event loop for ~lengths of time +function blockCpuFor(ms) { + var now = new Date().getTime(); + var result = 0 + while(true) { + result += Math.random() * Math.random(); + if (new Date().getTime() > now +ms) + return; + } +} + +// block the event loop for 100ms every second +setInterval(() => { + blockCpuFor(100); +}, 1000) + +// block the event loop for 1sec every 30 seconds +setInterval(() => { + blockCpuFor(1000); +}, 30000) + +// Allocate and erase memory on an interval +let store = []; + +setInterval(() => { + store.push(crypto.randomBytes(1000000).toString('hex')); +}, 500); + +setInterval(() => { + store = []; +}, 60000); + +const server = http.createServer((req, res) => { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.end("Hello, world!"); +}) + +server.listen(PORT, () => console.log(`Listening on ${PORT}`)); diff --git a/spec/fixtures/repos/node-14/package.json b/spec/fixtures/repos/node-14/package.json new file mode 100644 index 000000000..9a264cb2d --- /dev/null +++ b/spec/fixtures/repos/node-14/package.json @@ -0,0 +1,21 @@ +{ + "name": "hello-world", + "version": "1.0.0", + "engines": { + "node": "14.x" + }, + "scripts": { + "prettify": "prettier --single-quote --trailing-comma all --write 'bin/*' 'src/**/*.js'", + "test": "jest --silent", + "dev": "nodemon --watch . --watch src/* src/index.js", + "build": "echo NODE_OPTIONS: $NODE_OPTIONS" + }, + "main": "index.js", + "license": "MIT", + "devDependencies": { + "jest": "^19.0.2", + "nodemon": "^1.19.4", + "prettier": "^0.22.0" + }, + "dependencies": {} +} diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 5103ffb9a..e9ec86219 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -63,12 +63,12 @@ def resolve_all_supported_node_versions(options = {}) result = run!("#{resolve_binary_path} list node") list = result.lines().map { |line| line.split(' ').first } list.select do |n| - SemVersion.new(n).satisfies?('>= 6.0.0') + SemVersion.new(n).satisfies?('>= 10.0.0') end end def version_supports_metrics(version) - SemVersion.new(version).satisfies?('>= 8.0.0') && SemVersion.new(version).satisfies?('< 14.0.0') + SemVersion.new(version).satisfies?('>= 10.0.0') && SemVersion.new(version).satisfies?('< 15.0.0') end def get_test_versions @@ -77,7 +77,7 @@ def get_test_versions elsif ENV['TEST_ALL_NODE_VERSIONS'] == 'true' versions = resolve_all_supported_node_versions() else - versions = resolve_node_version(['6.x', '8.x', '9.x', '10.x', '11.x']) + versions = resolve_node_version(['10.x', '12.x', '13.x', '14.x']) end puts("Running tests for Node versions: #{versions.join(', ')}") versions From f12a83abe168232fa7a36ab16b4083eec587d43b Mon Sep 17 00:00:00 2001 From: Danielle Adams Date: Mon, 27 Apr 2020 08:53:58 -0400 Subject: [PATCH 2/2] update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddeb259f4..164e5b0f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Up feature flag test groups ([#758](https://github.com/heroku/heroku-buildpack-nodejs/pull/758)) - Add Heroku-20 to the Travis test matrix ([#763](https://github.com/heroku/heroku-buildpack-nodejs/pull/763)) - Add Node 14 plugin and rebuild 10, 12, and 13; Remove rebuilding of 8, 9, and 11 ([#767](https://github.com/heroku/heroku-buildpack-nodejs/pull/767)) +- Add spec support for Node 13 and 14 ([#766](https://github.com/heroku/heroku-buildpack-nodejs/pull/766)) ## v170 (2020-03-31) - Bump rake from 12.3.1 to 12.3.3 ([#742](https://github.com/heroku/heroku-buildpack-nodejs/pull/742))