From 3fb13500265704050f7ceb3b6deb48c2429cc3a1 Mon Sep 17 00:00:00 2001 From: Joe Goggins Date: Fri, 24 Jun 2022 17:06:30 -0500 Subject: [PATCH 1/9] Add options to EventStream constructor with blank header default key --- src/EventStream.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/EventStream.js b/src/EventStream.js index b3b2e93..841cf91 100644 --- a/src/EventStream.js +++ b/src/EventStream.js @@ -5,7 +5,15 @@ import url from 'url'; import { EventEmitter } from 'events'; class EventStream extends EventEmitter { - constructor(uri, token) { + /** + * + * @param {String} uri Event stream URL + * @param {String} token Particle Access Token + * @param {Object} options + * @param {Particle} options.headers key/val http headers to pass along + * @hideconstructor + */ + constructor(uri, token, options={ headers:{} }) { super(); this.uri = uri; this.token = token; @@ -13,6 +21,7 @@ class EventStream extends EventEmitter { this.timeout = 13000; // keep alive can be sent up to 12 seconds after last event this.data = ''; this.buf = ''; + this.options = options; this.parse = this.parse.bind(this); this.end = this.end.bind(this); From 988ab8f5445485e2654331551c52a4620b7e0157 Mon Sep 17 00:00:00 2001 From: Joe Goggins Date: Fri, 24 Jun 2022 17:08:25 -0500 Subject: [PATCH 2/9] EventStream connect() passes http headers to http request method --- src/EventStream.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/EventStream.js b/src/EventStream.js index 841cf91..b8cc577 100644 --- a/src/EventStream.js +++ b/src/EventStream.js @@ -41,7 +41,8 @@ class EventStream extends EventEmitter { path: `${path}?access_token=${this.token}`, method: 'get', port: parseInt(port, 10) || (isSecure ? 443 : 80), - mode: 'prefer-streaming' + mode: 'prefer-streaming', + headers: this.options.headers }); this.req = req; From fd847f9f5845c15228ded665a489725395327f4f Mon Sep 17 00:00:00 2001 From: Joe Goggins Date: Fri, 24 Jun 2022 17:09:43 -0500 Subject: [PATCH 3/9] .getEventStream() computes http headers via _getDefaultHttpHeadersForContext() --- src/Particle.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Particle.js b/src/Particle.js index 8d8093e..6f9b1d5 100644 --- a/src/Particle.js +++ b/src/Particle.js @@ -892,7 +892,25 @@ class Particle { } auth = this._getActiveAuthToken(auth); - return new EventStream(`${this.baseUrl}${uri}`, auth).connect(); + const headers = this._getDefaultHttpHeadersForContext(); + return new EventStream(`${this.baseUrl}${uri}`, auth, { headers }).connect(); + } + + /** + * A reimplementation of Agent's _addToolContext() and _addProjectContext() methods + * that can be used by getEventStream() which doesn't use Agent for http interactions + * @private + * @returns {Object} key/value http headers + */ + _getDefaultHttpHeadersForContext() { + const returnThis = {}; + if (this.context && this.context.tool) { + returnThis['X-Particle-Tool'] = `${this.context.tool.name}@${this.context.tool.version}`; + } + if (this.context && this.context.project) { + returnThis['X-Particle-Project'] = `${this.context.project.name}@${this.context.project.version}`; + } + return returnThis; } /** From 8cfbc8925bda61d36576b4a837dfc43c25bfa566 Mon Sep 17 00:00:00 2001 From: Joe Goggins Date: Fri, 24 Jun 2022 17:10:40 -0500 Subject: [PATCH 4/9] Adds test to validate EventStream connect passes on http headers --- test/EventStream.spec.js | 9 ++++++--- test/Particle.spec.js | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/test/EventStream.spec.js b/test/EventStream.spec.js index 3f04683..fd3177c 100644 --- a/test/EventStream.spec.js +++ b/test/EventStream.spec.js @@ -1,7 +1,6 @@ import { sinon, expect } from './test-setup'; import http from 'http'; import { EventEmitter } from 'events'; - import EventStream from '../src/EventStream'; describe('EventStream', () => { @@ -42,7 +41,10 @@ describe('EventStream', () => { return fakeRequest; }); - const eventStream = new EventStream('http://hostname:8080/path', 'token'); + const fakeToolName = 'fake'; + const fakeToolVersion = '1.2.3'; + const headers = { 'X-Particle-Tool': `${fakeToolName}@${fakeToolVersion}` }; + const eventStream = new EventStream('http://hostname:8080/path', 'token', { headers }); return eventStream.connect().then(() => { expect(http.request).to.have.been.calledWith({ @@ -51,7 +53,8 @@ describe('EventStream', () => { path: '/path?access_token=token', method: 'get', port: 8080, - mode: 'prefer-streaming' + mode: 'prefer-streaming', + headers }); }); }); diff --git a/test/Particle.spec.js b/test/Particle.spec.js index 5a6ee09..3e516b8 100644 --- a/test/Particle.spec.js +++ b/test/Particle.spec.js @@ -929,7 +929,7 @@ describe('ParticleAPI', () => { describe('.getEventStream', () => { before(() => { sinon.stub(EventStream.prototype, 'connect').callsFake(function connect(){ - return Promise.resolve({ uri: this.uri }); + return Promise.resolve({ uri: this.uri, options: this.options }); }); }); From f65b727a8d2d810ecac5a623592d5a84b2241908 Mon Sep 17 00:00:00 2001 From: Joe Goggins Date: Fri, 24 Jun 2022 17:11:26 -0500 Subject: [PATCH 5/9] Adds getEventStream tests that validate X-Particle-Tool and X-Particle-Project http headers get set as we'd expect when using setContext('tool') or setContext('project') --- test/Particle.spec.js | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/test/Particle.spec.js b/test/Particle.spec.js index 3e516b8..57f4db7 100644 --- a/test/Particle.spec.js +++ b/test/Particle.spec.js @@ -937,6 +937,44 @@ describe('ParticleAPI', () => { sinon.restore(); }); + describe('http headers', () => { + it('initializes options correctly with a blank headers object', async () => { + const { options } = await api.getEventStream({}); + expect(options).to.be.an('object'); + expect(options.headers).to.be.an('object'); + }); + + it('determines http headers using ._getDefaultHttpHeadersForContext()', async () => { + const fakeHeaders = { 'X-Fake-Header': 'foo' }; + sinon.stub(api, '_getDefaultHttpHeadersForContext').returns(fakeHeaders); + const { options } = await api.getEventStream({}); + expect(options).to.be.an('object'); + expect(options.headers).to.eql(fakeHeaders); + }); + + describe('._getDefaultHttpHeadersForContext() (a way to get http headers from context)', () => { + + it('returns empty object when no context has been set', () => { + expect(api._getDefaultHttpHeadersForContext()).to.eql({}); + }); + + it('includes X-Particle-Tool when this.context.tool is set', () => { + api.setContext('tool', { name: 'fake', version: '1.2.3' }); + const r = api._getDefaultHttpHeadersForContext(); + expect(r).to.be.an('object'); + expect(r['X-Particle-Tool']).to.eql('fake@1.2.3'); + }); + + it('includes X-Particle-Project when this.context.project is set', () => { + api.setContext('project', { name: 'fake', version: '1.2.3' }); + const r = api._getDefaultHttpHeadersForContext(); + expect(r).to.be.an('object'); + expect(r['X-Particle-Project']).to.eql('fake@1.2.3'); + }); + }); + + }); + it('requests public events', () => { return api.getEventStream({ }).then(({ uri }) => { uri.should.endWith('events'); From 876be72457666cfe073d78e59d1bfbb63de24f45 Mon Sep 17 00:00:00 2001 From: Joe Goggins Date: Fri, 24 Jun 2022 17:12:26 -0500 Subject: [PATCH 6/9] Adject linter to allow anonymous async functions in mocha Specifically, this change makes this linter error go away: /Users/me/git/particle-api-js/test/Particle.spec.js:941:78: Parsing error: Unexpected token => [Error]` --- .eslintrc.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.eslintrc.js b/.eslintrc.js index 5537238..1632ede 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,7 +1,8 @@ module.exports = { extends: ['eslint-config-particle'], parserOptions: { - sourceType: 'module' + sourceType: 'module', + ecmaVersion: 8 }, env: { browser: true, From 74689a085af786d90af9503468b5f0c18ce103d5 Mon Sep 17 00:00:00 2001 From: Joe Goggins Date: Fri, 24 Jun 2022 17:36:08 -0500 Subject: [PATCH 7/9] Tooling bugfix: Move tests not designed to run in CI into their own dir This makes it so that PARTICLE_API_TOKEN and PARTICLE_API_BASE_URL don't have to be specified for `npm run test:unit` and other npm run commands --- {test => e2e-tests}/EventStream-e2e-browser.html | 0 {test => e2e-tests}/EventStream-e2e-node.js | 2 +- {test => e2e-tests}/EventStream.feature | 0 e2e-tests/README.md | 8 ++++++++ 4 files changed, 9 insertions(+), 1 deletion(-) rename {test => e2e-tests}/EventStream-e2e-browser.html (100%) rename {test => e2e-tests}/EventStream-e2e-node.js (91%) rename {test => e2e-tests}/EventStream.feature (100%) create mode 100644 e2e-tests/README.md diff --git a/test/EventStream-e2e-browser.html b/e2e-tests/EventStream-e2e-browser.html similarity index 100% rename from test/EventStream-e2e-browser.html rename to e2e-tests/EventStream-e2e-browser.html diff --git a/test/EventStream-e2e-node.js b/e2e-tests/EventStream-e2e-node.js similarity index 91% rename from test/EventStream-e2e-node.js rename to e2e-tests/EventStream-e2e-node.js index 82c8cf5..e4bb1f0 100644 --- a/test/EventStream-e2e-node.js +++ b/e2e-tests/EventStream-e2e-node.js @@ -4,7 +4,7 @@ End-to-end test program for the event stream with Node Steps: - npm run compile -- PARTICLE_API_TOKEN= node test/EventStream-e2e-node.js +- PARTICLE_API_TOKEN= node e2e-tests/EventStream-e2e-node.js - Follow the scenarios in EventStream.feature */ diff --git a/test/EventStream.feature b/e2e-tests/EventStream.feature similarity index 100% rename from test/EventStream.feature rename to e2e-tests/EventStream.feature diff --git a/e2e-tests/README.md b/e2e-tests/README.md new file mode 100644 index 0000000..1b6ea9c --- /dev/null +++ b/e2e-tests/README.md @@ -0,0 +1,8 @@ +The tests in this directory do not run in CI. + +They can be used to do deep validations on the behavior of the library against the actual Particle API + +Follow the directions at in each script for how to use them. + +Also, you'll need set valid values for env vars like PARTICLE_API_BASE_URL +and PARTICLE_API_TOKEN \ No newline at end of file From 00176ae47eaddcefa393afac0df05b45428085fd Mon Sep 17 00:00:00 2001 From: Joe Goggins Date: Fri, 24 Jun 2022 17:47:07 -0500 Subject: [PATCH 8/9] Update docs to reflect not needing to set env vars --- README.md | 2 -- e2e-tests/README.md | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5b40d49..4dad761 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,6 @@ All essential commands are available at the root via `npm run