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

Attempt to deflakify joining test #3956

Merged
merged 3 commits into from
May 18, 2017
Merged
Changes from 1 commit
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
183 changes: 125 additions & 58 deletions test/mock-request.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";
var q = require("q");
var expect = require('expect');
const q = require("q");
import expect from 'expect';

/**
* Construct a mock HTTP backend, heavily inspired by Angular.js.
Expand All @@ -9,23 +9,25 @@ var expect = require('expect');
function HttpBackend() {
this.requests = [];
this.expectedRequests = [];
var self = this;
const self = this;
// the request function dependency that the SDK needs.
this.requestFn = function(opts, callback) {
var realReq = new Request(opts.method, opts.uri, opts.body, opts.qs);
realReq.callback = callback;
console.log("HTTP backend received request: %s %s", opts.method, opts.uri);
self.requests.push(realReq);
const req = new Request(opts, callback);
console.log("HTTP backend received request: %s", req);
self.requests.push(req);

var abort = function() {
var idx = self.requests.indexOf(realReq);
const abort = function() {
const idx = self.requests.indexOf(req);
if (idx >= 0) {
console.log("Aborting HTTP request: %s %s", opts.method, opts.uri);
console.log("Aborting HTTP request: %s %s", opts.method,
opts.uri);
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't seem necessary unless it was to reduce line length?

Copy link
Member Author

Choose a reason for hiding this comment

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

oh, it just came with the c&p from js-sdk. Where it probably did happen to reduce line length.

Copy link
Contributor

Choose a reason for hiding this comment

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

ah ok

self.requests.splice(idx, 1);
req.callback("aborted");
}
}
};

return {
abort: abort
abort: abort,
};
};
}
Expand All @@ -34,43 +36,48 @@ HttpBackend.prototype = {
* Respond to all of the requests (flush the queue).
* @param {string} path The path to flush (optional) default: all.
* @param {integer} numToFlush The number of things to flush (optional), default: all.
* @return {Promise} resolved when there is nothing left to flush.
* @param {integer=} waitTime The time (in ms) to wait for a request to happen.
* default: 5
*
* @return {Promise} resolves when there is nothing left to flush, with the
* number of requests flushed
*/
flush: function(path, numToFlush) {
var defer = q.defer();
var self = this;
var flushed = 0;
var triedWaiting = false;
flush: function(path, numToFlush, waitTime) {
const defer = q.defer();
const self = this;
let flushed = 0;
let triedWaiting = false;
if (waitTime === undefined) {
waitTime = 5;
}
console.log(
"HTTP backend flushing... (path=%s numToFlush=%s)", path, numToFlush
"HTTP backend flushing... (path=%s numToFlush=%s waitTime=%s)",
path, numToFlush, waitTime,
);
var tryFlush = function() {
const tryFlush = function() {
// if there's more real requests and more expected requests, flush 'em.
console.log(
" trying to flush queue => reqs=%s expected=%s [%s]",
self.requests.length, self.expectedRequests.length, path
" trying to flush queue => reqs=[%s] expected=[%s]",
self.requests, self.expectedRequests.map((er) => er.path),
);
if (self._takeFromQueue(path)) {
// try again on the next tick.
console.log(" flushed. Trying for more. [%s]", path);
flushed += 1;
if (numToFlush && flushed === numToFlush) {
console.log(" [%s] Flushed assigned amount: %s", path, numToFlush);
defer.resolve();
}
else {
console.log(" Flushed assigned amount: %s", numToFlush);
defer.resolve(flushed);
} else {
console.log(" flushed. Trying for more.");
setTimeout(tryFlush, 0);
}
}
else if (flushed === 0 && !triedWaiting) {
} else if (flushed === 0 && !triedWaiting) {
// we may not have made the request yet, wait a generous amount of
// time before giving up.
setTimeout(tryFlush, 5);
setTimeout(tryFlush, waitTime);
triedWaiting = true;
}
else {
console.log(" no more flushes. [%s]", path);
defer.resolve();
} else {
console.log(" no more flushes.");
defer.resolve(flushed);
}
};

Expand All @@ -85,14 +92,19 @@ HttpBackend.prototype = {
* @return {boolean} true if something was resolved.
*/
_takeFromQueue: function(path) {
var req = null;
var i, j;
var matchingReq, expectedReq, testResponse = null;
let req = null;
let i;
let j;
let matchingReq = null;
let expectedReq = null;
let testResponse = null;
for (i = 0; i < this.requests.length; i++) {
req = this.requests[i];
for (j = 0; j < this.expectedRequests.length; j++) {
expectedReq = this.expectedRequests[j];
if (path && path !== expectedReq.path) { continue; }
if (path && path !== expectedReq.path) {
continue;
}
if (expectedReq.method === req.method &&
req.path.indexOf(expectedReq.path) !== -1) {
if (!expectedReq.data || (JSON.stringify(expectedReq.data) ===
Expand All @@ -114,12 +126,12 @@ HttpBackend.prototype = {
}
testResponse = matchingReq.response;
console.log(" responding to %s", matchingReq.path);
var body = testResponse.body;
let body = testResponse.body;
if (Object.prototype.toString.call(body) == "[object Function]") {
body = body(req.path, req.data);
}
req.callback(
testResponse.err, testResponse.response, body
testResponse.err, testResponse.response, body,
);
matchingReq = null;
}
Expand All @@ -134,23 +146,20 @@ HttpBackend.prototype = {
* Makes sure that the SDK hasn't sent any more requests to the backend.
*/
verifyNoOutstandingRequests: function() {
var firstOutstandingReq = this.requests[0] || {};
const firstOutstandingReq = this.requests[0] || {};
expect(this.requests.length).toEqual(0,
"Expected no more HTTP requests but received request to " +
firstOutstandingReq.path
firstOutstandingReq.path,
);
},

/**
* Makes sure that the test doesn't have any unresolved requests.
*/
verifyNoOutstandingExpectation: function() {
var firstOutstandingExpectation = this.expectedRequests[0] || {};
expect(this.expectedRequests.length).toEqual(
0,
"Expected to see HTTP request for "
+ firstOutstandingExpectation.method
+ " " + firstOutstandingExpectation.path
const firstOutstandingExpectation = this.expectedRequests[0] || {};
expect(this.expectedRequests.length).toEqual(0,
"Expected to see HTTP request for " + firstOutstandingExpectation.path,
);
},

Expand All @@ -162,22 +171,32 @@ HttpBackend.prototype = {
* @return {Request} An expected request.
*/
when: function(method, path, data) {
var pendingReq = new Request(method, path, data);
const pendingReq = new ExpectedRequest(method, path, data);
this.expectedRequests.push(pendingReq);
return pendingReq;
}
},
};

function Request(method, path, data, queryParams) {
/**
* Represents the expectation of a request.
*
* <p>Includes the conditions to be matched against, the checks to be made,
* and the response to be returned.
*
* @constructor
* @param {string} method
* @param {string} path
* @param {object?} data
*/
function ExpectedRequest(method, path, data) {
this.method = method;
this.path = path;
this.data = data;
this.queryParams = queryParams;
this.callback = null;
this.response = null;
this.checks = [];
}
Request.prototype = {

ExpectedRequest.prototype = {
/**
* Execute a check when this request has been satisfied.
* @param {Function} fn The function to execute.
Expand All @@ -198,10 +217,10 @@ Request.prototype = {
this.response = {
response: {
statusCode: code,
headers: {}
headers: {},
},
body: data,
err: null
err: null,
};
},

Expand All @@ -214,14 +233,62 @@ Request.prototype = {
this.response = {
response: {
statusCode: code,
headers: {}
headers: {},
},
body: null,
err: err
err: err,
};
},
};

/**
* Represents a request made by the app.
*
* @constructor
* @param {object} opts opts passed to request()
* @param {function} callback
*/
function Request(opts, callback) {
this.opts = opts;
this.callback = callback;

Object.defineProperty(this, 'method', {
get: function() {
return opts.method;
},
});

Object.defineProperty(this, 'path', {
get: function() {
return opts.uri;
},
});

Object.defineProperty(this, 'data', {
get: function() {
return opts.body;
},
});

Object.defineProperty(this, 'queryParams', {
get: function() {
return opts.qs;
},
});

Object.defineProperty(this, 'headers', {
get: function() {
return opts.headers || {};
},
});
}

Request.prototype = {
toString: function() {
return this.method + " " + this.path;
},
};

/**
* The HttpBackend class.
*/
Expand Down