Skip to content

Commit 5746c89

Browse files
Merge pull request #28 from ember-codemods/suchita/single-telemetry
Add single telemetry support
2 parents f95e43a + f7f32fd commit 5746c89

File tree

7 files changed

+146
-11
lines changed

7 files changed

+146
-11
lines changed

lib/gather/gather-single-telemetry.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
const puppeteer = require('puppeteer');
2+
const { setTelemetryWithKey } = require('../utils/telemetry');
3+
4+
const DEFAULT_PUPPETEER_ARGS = { ignoreHTTPSErrors: true };
5+
6+
module.exports = async function gatherSingleTelemetry(url, options = {}, gatherFn, ...args) {
7+
const browser = await puppeteer.launch(DEFAULT_PUPPETEER_ARGS);
8+
const page = await browser.newPage();
9+
10+
await page.goto(url);
11+
12+
await page.exposeFunction('logErrorInNodeProcess', message => {
13+
console.error(message); // eslint-disable-line no-console
14+
});
15+
16+
const telemetry = await bridgeEvaluate(
17+
page,
18+
async (gFn, ...supportFns) => {
19+
supportFns.forEach(fn => {
20+
this[fn.name] = fn;
21+
});
22+
let telemetry = {};
23+
24+
telemetry = await gFn(...supportFns);
25+
return telemetry;
26+
},
27+
gatherFn,
28+
...args
29+
);
30+
31+
setTelemetryWithKey(options.telemetryKey, telemetry);
32+
await browser.close();
33+
34+
async function bridgeEvaluate(page, fn, ...rawArgs) {
35+
const args = await Promise.all(
36+
rawArgs.map(arg => {
37+
return typeof arg === 'function' ? page.evaluateHandle(`(${arg.toString()})`) : arg;
38+
})
39+
);
40+
return page.evaluate(fn, ...args);
41+
}
42+
};
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
const startApp = require('../../test/helpers/start-app');
2+
const gatherSingleTelemetry = require('./gather-single-telemetry');
3+
const { getTelemetry } = require('../utils/telemetry');
4+
const APP_TIMEOUT = 100000;
5+
const TELEMETRY_KEY = 'single-telemetry';
6+
7+
function resolverWithoutArgs() {
8+
return { foo: 'bar' };
9+
}
10+
11+
function resolverWithArgs(lookupNames) {
12+
if (lookupNames) {
13+
return lookupNames.map(item => {
14+
const lookupSplit = item.split(':');
15+
return { name: lookupSplit[1], type: lookupSplit[0] };
16+
});
17+
}
18+
}
19+
20+
describe('Gather single telemetry', () => {
21+
let app;
22+
let localAppPath = './test/fixtures/classic-app';
23+
beforeAll(async () => {
24+
app = await startApp(localAppPath);
25+
console.log(`Spawned PID: ${app.emberServe.pid}`);
26+
}, APP_TIMEOUT);
27+
28+
test('can determine base single telemetry case', async () => {
29+
await gatherSingleTelemetry(
30+
'http://localhost:4200',
31+
{ telemetryKey: TELEMETRY_KEY },
32+
resolverWithoutArgs
33+
);
34+
let telemetry = getTelemetry(TELEMETRY_KEY);
35+
expect(telemetry).toEqual({
36+
foo: 'bar',
37+
});
38+
});
39+
40+
test('can determine single telemetry with arguments passed', async () => {
41+
const lookupNames = ['component:foo', 'helper:bar'];
42+
await gatherSingleTelemetry(
43+
'http://localhost:4200',
44+
{ telemetryKey: TELEMETRY_KEY },
45+
resolverWithArgs,
46+
lookupNames
47+
);
48+
let telemetry = getTelemetry(TELEMETRY_KEY);
49+
expect(telemetry).toEqual([
50+
{ name: 'foo', type: 'component' },
51+
{ name: 'bar', type: 'helper' },
52+
]);
53+
});
54+
55+
afterAll(async () => {
56+
console.log(`Killing PID: ${app.emberServe.pid}`);
57+
await app.emberServe.shutdown();
58+
}, APP_TIMEOUT);
59+
});

lib/gather/gather-telemetry.test.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,6 @@ describe('Provide a personalized `Gathering Function`', () => {
6969

7070
afterAll(async () => {
7171
console.log(`Killing PID: ${app.emberServe.pid}`);
72-
await app.emberServe.kill('SIGTERM', {
73-
forceKillAfterTimeout: 200,
74-
});
72+
await app.emberServe.shutdown();
7573
}, APP_TIMEOUT);
7674
});

lib/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const gatherTelemetryForUrl = require('./gather/gather-telemetry');
2+
const gatherSingleTelemetryForUrl = require('./gather/gather-single-telemetry.js');
23
const { getModulePathFor } = require('./utils/get-module-path-for');
34
const { getTelemetry, setTelemetry, getTelemetryFor } = require('./utils/telemetry');
45
const analyzeEmberObject = require('./gather/analyze-ember-object');
@@ -7,6 +8,7 @@ module.exports = {
78
getTelemetry,
89
setTelemetry,
910
gatherTelemetryForUrl,
11+
gatherSingleTelemetryForUrl,
1012
getTelemetryFor,
1113
getModulePathFor,
1214
analyzeEmberObject,

lib/utils/telemetry.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,23 @@ const { getModulePathFor } = require('./get-module-path-for');
44
const CACHE_KEY = 'telemetry';
55

66
function setTelemetry(newTelemetry) {
7-
let data = JSON.stringify(newTelemetry);
7+
setTelemetryWithKey(CACHE_KEY, newTelemetry);
8+
}
89

9-
cache.set(CACHE_KEY, data);
10+
function setTelemetryWithKey(cacheKey, newTelemetry) {
11+
let data = JSON.stringify(newTelemetry);
12+
cache.set(cacheKey, data);
1013
}
1114

12-
function getTelemetry() {
13-
let telemetryExists = cache.has(CACHE_KEY);
15+
function getTelemetry(cacheKey) {
16+
cacheKey = cacheKey || CACHE_KEY;
17+
let telemetryExists = cache.has(cacheKey);
1418

1519
if (!telemetryExists) {
1620
return {};
1721
}
1822

19-
let telemetryData = cache.get(CACHE_KEY).value;
23+
let telemetryData = cache.get(cacheKey).value;
2024
let telemetry = {};
2125

2226
try {
@@ -51,5 +55,6 @@ function _generateModuleKey(modulePath) {
5155
module.exports = {
5256
getTelemetry,
5357
setTelemetry,
58+
setTelemetryWithKey,
5459
getTelemetryFor,
5560
};

lib/utils/telemetry.test.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { getTelemetry, setTelemetry, getTelemetryFor } = require('./telemetry');
1+
const { getTelemetry, setTelemetry, setTelemetryWithKey, getTelemetryFor } = require('./telemetry');
22

33
describe('get/set Telemetry', () => {
44
test('can get the set telemetry', () => {
@@ -16,6 +16,22 @@ describe('get/set Telemetry', () => {
1616
});
1717
});
1818

19+
describe('get/set Telemetry with keys', () => {
20+
test('can get the set telemetry with keys', () => {
21+
let fakeTelemetry = {
22+
a: 1,
23+
b: 2,
24+
};
25+
26+
setTelemetryWithKey('fake-telemetry', fakeTelemetry);
27+
28+
let telemetry = getTelemetry('fake-telemetry');
29+
30+
expect(Object.keys(telemetry)).toEqual(Object.keys(fakeTelemetry));
31+
expect(Object.values(telemetry)).toEqual(Object.values(fakeTelemetry));
32+
});
33+
});
34+
1935
describe('getTelemetryFor', () => {
2036
test('gets the data for the filePath', () => {
2137
let fakeTelemetry = { a: 1 };

test/helpers/start-app.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@ const path = require('path');
33

44
module.exports = async function startApp(appPath) {
55
const classicAppDir = path.resolve(appPath);
6-
const execOpts = { cwd: classicAppDir, stderr: 'inherit' };
6+
const execOpts = { cwd: classicAppDir, stderr: 'inherit', preferLocal: true };
77
console.log('installing deps');
88

99
await execa('rm', ['-rf', 'node_modules'], execOpts);
1010
await execa('yarn', ['install'], execOpts);
1111

1212
console.log('starting serve');
13-
const emberServe = execa('yarn', ['start'], execOpts);
13+
14+
// `yarn` has a bug where even if the process gets killed, it leaves the child process (ember in this case) orphaned.
15+
// Hence we are using `ember` directly here to overcome the above shortcoming and ensure that the ember process is always killed
16+
// cleanly.
17+
const emberServe = execa('ember', ['serve'], execOpts);
1418
emberServe.stdout.pipe(process.stdout);
1519

1620
await new Promise(resolve => {
@@ -22,5 +26,14 @@ module.exports = async function startApp(appPath) {
2226
});
2327
});
2428

29+
emberServe.shutdown = async function() {
30+
this.kill();
31+
try {
32+
await this;
33+
} catch (e) {
34+
// Process is allowed to exit with a non zero exit status code.
35+
}
36+
};
37+
2538
return { emberServe };
2639
};

0 commit comments

Comments
 (0)