Skip to content
This repository has been archived by the owner on Sep 16, 2019. It is now read-only.

add gosquared #14

Merged
merged 1 commit into from
May 17, 2017
Merged

add gosquared #14

merged 1 commit into from
May 17, 2017

Conversation

craigmulligan
Copy link
Contributor

Connects to #13

This adds gosquared for browser and node.js, it keeps the modules current handling of non authenticated uses as mentioned in #12 (will handle that in a seperate PR).

Current issue is that I can't get the browser tests to pass for gosquared. I've tested it manually in a browser and it works but with karma the nock request is never fulfilled and I'm struggling to debug effectively.

The nockRequest.isDone() continues to return false, I'm confident the track method is being called.

Any ideas?

I saw something about xhr transport that's needed for the ga tests? Could it be related?

Change-type: minor

@emirotin
Copy link
Contributor

The tests seem to be OK now?

karmaConfig.sauceLabs = {
testName: packageJSON.name + ' v' + packageJSON.version
}
karmaConfig.browserConsoleLogOptions = {
level: 'log',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spaces/tabs

@@ -7,7 +7,8 @@
"bluebird": "^3.4.7",
"lodash": "^4.0.0",
"resin-mixpanel-client": "^2.1.0",
"resin-universal-ga": "^1.1.0"
"resin-universal-ga": "^1.1.0",
"resin-universal-gosquared": "*"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't use *, use the proper semver range (like ^0.1.0)

@@ -11,7 +11,8 @@ var EVENTS = {
application: [ 'create', 'open', 'delete', 'osDownload' ],
environmentVariable: [ 'create', 'edit', 'delete' ],
device: [ 'open', 'rename', 'delete', 'terminalOpen', 'terminalClose' ],
deviceEnvironmentVariable: [ 'create', 'edit', 'delete' ]
deviceEnvironmentVariable: [ 'create', 'edit', 'delete' ],
page: [ 'view' ]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is visit a better name?


module.exports = function (options) {
var debug = options.debug,
gosquaredId = options.gosquaredId
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing comma means the following two vars are global

apiKey = options.gosquaredApiKey
isBrowser = typeof window !== 'undefined'

if (!(gosquaredId)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unneeded extra parens

@@ -95,6 +97,7 @@ module.exports = function(options) {
hooks.afterCreate.call(_this, err, type, jsonData, applicationId, deviceId)
}).catch(function (err) {
// discard the hook error
console.log('OMGerr', err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OMGerr

@@ -114,6 +117,39 @@ function createGaMock(endpoint) {
return aggregateMock(mocks)
}

function validateGsQuery(event) {
return true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to get the test to pass by just returning straight away

return true
}

if (!IS_BROWSER) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unneeded check because of the previous guard

if (!IS_BROWSER) {
return (
event.site_token === GOSQUARED_ID
&& event.api_key === GOSQUARED_API_KEY
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to keep the operator && on the prev line

@craigmulligan
Copy link
Contributor Author

craigmulligan commented Apr 21, 2017

The tests were passing because I had altered them to not depend on the mocked request getting resolved.

Basically the xhr-mock is never hit :/ I checked the event function is fired and that the would be request matches the regex. I watching the monitoring it with wireshark but I'm not seeing anything coming from karma. Probably a fault of me not using wireshark correctly.

@pimterry
Copy link
Contributor

Oh, bonus point on this @craig-mulligan: even without Chrome here, generally you don't want to use Wireshark for HTTP, it's way too complicated.

Try http://www.telerik.com/fiddler or https://www.charlesproxy.com/ - they're both HTTP proxies for testing. Way way easier for HTTP stuff, and also have built in support for things like MitM inspection on HTTPS, and header and json parsing etc.

@craigmulligan
Copy link
Contributor Author

@pimterry, @emirotin I got to the bottom of it (sort of)

Tests were really hard to write, because of series of peculiarities with the go squared tracking script.

First go squared doesn’t make xhr requests it instead loads the requests by adding a script tag with the endpoint as the src to the for each request. Which means I couldn’t access it from the test script.

Phantom.js does have a onResourceRequested api hook which can tell me when resource was called but it only ever fires for the first request made to gosquared, some others have hit this too (if I use window.performace.getEntriesByType('resource') in chrome I can see all the requests. Unfortunately phantom.js doesn't have that browser api implemented.

Secondly gosquared it only triggers an event request after a page view is called. And thirdly it randomises it’s hostname, between data2.gosquared and data.gosquared. Which made request tracking a mission.

Anyway, I've implemented some checks which use the onResourceRequested hook I mentioned, although currently all the browser tests do is check that a request was made to gosquared.com unfortunately without phantom.js onResourceRequested working properly I can’t get much further.

Any better ideas on ways to test this?

I’ve asked gosquared for a debug version of tracker.js that sends xhr requests, but no response yet.

@craigmulligan
Copy link
Contributor Author

Ping @emirotin

@pimterry
Copy link
Contributor

@craig-mulligan Damn, that's going to be very annoying.

I'm feeling like the current mocking code has caused us a few problems, because so many of these libraries do strange things. Should we try refactoring this to a different approach? Can we set up an actual proxy server, and then point PhantomJS/Node to that when we start it up, and use that to intercept and check all the requests? Should be drastically more reliable and easier to debug. Potentially slightly slower and a little more complicated internally, but could be worth it imo, if it's possible.

I've got a basic implementation of programmable proxy server for testing with Node from a while back, which might be useful if we do want to try this: https://www.npmjs.com/package/http-server-mock. It's mostly stubbing right now, rather than mocking, but you could extend it fairly easily. No docs, but there's a bunch of usage for AWS stubbing that should cover the current API, e.g: https://github.com/pimterry/dev-bot-tool/blob/master/test/integration/aws-deploy-test.ts#L30 + https://github.com/pimterry/dev-bot-tool/blob/master/test/helpers/aws-mocks.ts#L8-L33.

The tricky bit is likely to be setting up, tearing down and communicating with a proxy server from inside the tests. I'm not totally sure how that'd work off the top of my head, but I'm pretty sure it's all possible. Other ideas welcome too!

@craigmulligan
Copy link
Contributor Author

Hey @pimterry I've been using this http://www.mock-server.com/ for a personal project I haven't touched the verification much but looks pretty http://www.mock-server.com/proxy/verification.html.It's written in Java :/ but has a javascript client to start/stop and add expectations.

What do you think?

@pimterry
Copy link
Contributor

pimterry commented May 2, 2017

@craig-mulligan that looks ok in principle, but I'd much rather we didn't have to depend on Java... Getting everybody who wants to develop this to have to install Java and get this set up will be annoying. Doesn't look like their Node module handles server startup either, only communication, so you'll need a Node script that's going to have to reliably manage a Java process in a neat cross platform way, and it's all just going to get nasty.

I'd be strongly tempted to just build one, either extending http-server-mock or otherwise. You just need a Node HTTP server that exposes a JSON api for mock configuration & verification, to start it up before the test suite, and to point the browser at that as a proxy. Should be relatively easy I think. Do you want to try putting together a small proof of concept of that inside this repo to get this working, and then we can look at building it into something more substantial and reliable once we've got these tests working and this PR merged?

@craigmulligan
Copy link
Contributor Author

@pimterry yea I just had a go at implementing the http://www.mock-server.com/. It has a client ect so you could do everything except the client isn't isomorphic so browsers tests fail.

A basic implementation would be a great help! Here is a script I was using to start the mock server before the tests.

@craigmulligan
Copy link
Contributor Author

@pimterry I've removed the browser tests. Should be good for review.

Copy link
Contributor

@pimterry pimterry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, but make sure @emirotin's happy too before we merge this.

@craigmulligan
Copy link
Contributor Author

Thanks Tim, @emirotin could you take another look?

logout: function() {
return gsClient.logout()
},
track: function (prefix, type, data) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why ignoring prefix?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I now pass them down like we do for mixpanel so events are named like so: [ prefix ] eventType.

@@ -114,8 +116,33 @@ function createGaMock(endpoint) {
return aggregateMock(mocks)
}

function validateGsQuery(event) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

event sounds misleading, it's the queryString, is it?

filterBody: function() { return true },
response: '1'
})
delete options.event
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is event, how does it end up in the options (I don't see it ever passed there) and why do we delete it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I was passing the expected event to check if it was in the querystring, because the browser passes it that way. But in node it passes it as the request body, I didn't clean up properly when removing the browser tests.

expect(mockedRequest.isDone()).to.be.ok
done()
} else {
// Don't mock browser tests see:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a big TODO

window,
document,
'script',
'https://d1l6p2sc9645hc.cloudfront.net/tracker.js',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Different indent

},
track: function(type, data) {
// if called before `login` create the object with the random ID
createVisitor()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently this will recreate the visitor. It will also drop the userId link which sounds wrong to me

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's wrong I need a if (visitor) return visitor in createVisitor.

@craigmulligan
Copy link
Contributor Author

@emirotin could you re-review :)

})

if (userId) {
gosquared.createPerson(userId)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These lines were different previously reading visitor = gosquared.createPerson(userId). Is it equivalent? Also I didn't find this method on the gosquared docs site

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, if you don't identify a user with .createPerson() the lib will handle it for you. So it think it's simpler to only assign a user if an id is provided.

See the on this example on this page it should clarify.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I'm saying is that you're not assigning the result of createPerson, the linked page doesn't make it clear to me this will have any effect.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see what you mean... and after looking at the source you are ofc right, it's a factory and does not update the instance.

@craigmulligan
Copy link
Contributor Author

@emirotin I went through it again after your last comment and found another bug where I didn't actually pass the user.id to go squared lib. I didn't catch with manual testing because i was using the browser and it was automatically generating ids.

I've fixed it and added a test case for node.

@emirotin
Copy link
Contributor

Would this be captured by node tests? Can we add some checks, like inside of the tracking verify that the proper user ID has been used?

filterBody: function (body, eventName) {
return (
body.event.name === '[' + SYSTEM + '] ' + EXPECTED_EVENT &&
body.person_id == FAKE_USER.id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT but can be strict comparison for consistency

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can't because user.id is a number and the body.person_id is a string. I can do explicit type conversion but implicit is better in this case no?

Copy link
Contributor

@emirotin emirotin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM but if you can improve the tests please do before merging.
Also please don't forget to squash the commits

@craigmulligan craigmulligan changed the title [WIP] add gosquared add gosquared May 16, 2017
@craigmulligan
Copy link
Contributor Author

@emirotin cool, what do you have in mind for improving the tests?

@emirotin
Copy link
Contributor

See my previous comment about catching the error you didn't notice with manual testing:

Would this be captured by node tests? Can we add some checks, like inside of the tracking (mock) verify that the proper user ID has been used?

@craigmulligan
Copy link
Contributor Author

yes, I've added a test case for that for gosquared. I'll see what effort is required for the other services.

@emirotin
Copy link
Contributor

oh, I didn't notice, I think it's good to merge then, if you can send a separate PR for other services - awesome :), but it doesn't have to block this one

Connects to #13

Change-type: minor
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants