Skip to content

Commit

Permalink
integrate support for GAE dev
Browse files Browse the repository at this point in the history
  • Loading branch information
stephenplusplus committed Feb 4, 2015
1 parent cd9487a commit a11254b
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 18 deletions.
32 changes: 24 additions & 8 deletions lib/common/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,21 @@ function makeWritableStream(dup, options, onComplete) {
module.exports.makeWritableStream = makeWritableStream;

function makeAuthorizedRequest(config) {
var GAE_OR_GCE = !config || (!config.credentials && !config.keyFile);
var ENV = {
GAE_DEV: process.env.GAE_LONG_APP_ID && !process.env.GAE_VM,
NO_CREDENTIALS: !config || (!config.credentials && !config.keyFile)
};

var authorize;

if (ENV.GAE_DEV && ENV.NO_CREDENTIALS) {
// Google App Engine Development mode doesn't require authorization.
authorize = function(reqOpts, callback) {
callback(null, reqOpts);
};
} else {
authorize = gsa(config);
}

var missingCredentialsError = new Error();
missingCredentialsError.message = [
Expand All @@ -357,8 +371,6 @@ function makeAuthorizedRequest(config) {
'\n'
].join('');

var authorize = gsa(config);

function makeRequest(reqOpts, callback) {
var tokenRefreshAttempts = 0;
reqOpts.headers = reqOpts.headers || {};
Expand All @@ -371,9 +383,8 @@ function makeAuthorizedRequest(config) {

function onAuthorizedRequest(err, authorizedReqOpts) {
if (err) {
if (GAE_OR_GCE && err.code === 'ENOTFOUND') {
// The metadata server wasn't found. The user must not actually be in
// a GAE or GCE environment.
if (ENV.NO_CREDENTIALS && err.code === 'ENOTFOUND') {
// The metadata server wasn't found. This must not be GAE or GCE.
throw missingCredentialsError;
}

Expand All @@ -385,8 +396,7 @@ function makeAuthorizedRequest(config) {

// For detecting Sign errors on io.js (1.x) (or node 0.11.x)
// E.g. errors in form: error:code:PEM routines:PEM_read_bio:error_name
var pemError = err.message &&
err.message.indexOf('error:') !== -1;
var pemError = err.message && err.message.indexOf('error:') !== -1;

if (err.message === 'SignFinal error' || pemError) {
err.message = [
Expand All @@ -412,6 +422,12 @@ function makeAuthorizedRequest(config) {
}

makeRequest.getCredentials = authorize.getCredentials;
makeRequest.getEnvironment = function() {
return {
GAE_DEV: ENV.GAE_DEV,
NO_CREDENTIALS: ENV.NO_CREDENTIALS
};
};

return makeRequest;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/datastore/dataset.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ function Dataset(options) {
return new Dataset(options);
}

options = options || {};
this.options = options = options || {};

this.makeAuthorizedRequest_ = util.makeAuthorizedRequest({
credentials: options.credentials,
Expand Down
20 changes: 17 additions & 3 deletions lib/datastore/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

'use strict';

var http = require('http');
var https = require('https');
var streamEvents = require('stream-events');
var through = require('through2');
Expand Down Expand Up @@ -209,7 +210,7 @@ DatastoreRequest.prototype.get = function(keys, callback) {
* //-
* var companyKey = dataset.key(['Company', 123]);
* var productKey = dataset.key(['Product', 'Computer']);
*
*
* dataset.save([
* {
* key: companyKey,
Expand Down Expand Up @@ -492,6 +493,8 @@ DatastoreRequest.prototype.allocateIds = function(incompleteKey, n, callback) {
* Make a request to the API endpoint. Properties to indicate a transactional or
* non-transactional operation are added automatically.
*
* @todo Handle non-HTTP 200 cases.
*
* @param {string} method - Datastore action (allocateIds, commit, etc.).
* @param {object=} body - Request configuration object.
* @param {function} callback - The callback function.
Expand All @@ -507,7 +510,8 @@ DatastoreRequest.prototype.allocateIds = function(incompleteKey, n, callback) {
* transaction.makeReq('commit', deleteRequest, function(err) {});
*/
DatastoreRequest.prototype.makeReq_ = function(method, body, callback) {
// TODO: Handle non-HTTP 200 cases.
var ENV = this.makeAuthorizedRequest_.getEnvironment();

if (!callback) {
callback = body;
body = {};
Expand Down Expand Up @@ -550,7 +554,17 @@ DatastoreRequest.prototype.makeReq_ = function(method, body, callback) {
return;
}

var remoteStream = https.request(authorizedReqOpts, function(resp) {
var remoteStream;

if (ENV.GAE_DEV && ENV.NO_CREDENTIALS) {
authorizedReqOpts.host = process.env.API_HOST;
authorizedReqOpts.port = process.env.GAE_SERVER_PORT;
remoteStream = http.request(authorizedReqOpts);
} else {
remoteStream = https.request(authorizedReqOpts);
}

remoteStream.on('response', function(resp) {
var buffer = new Buffer('');
resp.on('data', function(chunk) {
buffer = Buffer.concat([buffer, chunk]);
Expand Down
75 changes: 69 additions & 6 deletions test/datastore/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var assert = require('assert');
var ByteBuffer = require('bytebuffer');
var entity = require('../../lib/datastore/entity.js');
var extend = require('extend');
var http = require('http');
var https = require('https');
var mockery = require('mockery');
var mockRespGet = require('../testdata/response_get.json');
Expand All @@ -39,6 +40,15 @@ extend(true, https, {
}
});

var httpRequestCached = http.request;
var httpRequestOverride = util.noop;

extend(true, http, {
request: function() {
return httpRequestOverride.apply(this, util.toArray(arguments));
}
});

// Create a protobuf "FakeMethod" request & response.
pb.FakeMethodRequest = function() {
this.toBuffer = function() {
Expand All @@ -62,6 +72,7 @@ describe('Request', function() {
before(function() {
mockery.registerMock('./pb.js', pb);
mockery.registerMock('https', https);
mockery.registerMock('http', http);
mockery.enable({
useCleanCache: true,
warnOnUnregistered: false
Expand All @@ -73,6 +84,7 @@ describe('Request', function() {
mockery.deregisterAll();
mockery.disable();
httpsRequestOverride = httpsRequestCached;
httpRequestOverride = httpRequestCached;
});

beforeEach(function() {
Expand All @@ -85,6 +97,9 @@ describe('Request', function() {
request.makeAuthorizedRequest_ = function(req, callback) {
(callback.onAuthorized || callback)(null, req);
};
request.makeAuthorizedRequest_.getEnvironment = function() {
return {};
};
});

describe('get', function() {
Expand Down Expand Up @@ -487,10 +502,13 @@ describe('Request', function() {
assert.equal(opts.headers['Content-Type'], 'application/x-protobuf');
done();
};
request.makeAuthorizedRequest_.getEnvironment = function() {
return {};
};
request.makeReq_(method, {}, util.noop);
});

it('should make https request', function(done) {
it('should make https request if not gae dev and no creds', function(done) {
var mockRequest = { mock: 'request' };
httpsRequestOverride = function(req) {
assert.deepEqual(req, mockRequest);
Expand All @@ -500,6 +518,45 @@ describe('Request', function() {
request.makeAuthorizedRequest_ = function(opts, callback) {
(callback.onAuthorized || callback)(null, mockRequest);
};
request.makeAuthorizedRequest_.getEnvironment = function() {
return {
GAE_DEV: false,
NO_CREDENTIALS: false
};
};
request.makeReq_('commit', {}, util.noop);
});

it('should make http call to API_HOST if no credentials', function(done) {
var mockRequest = { mock: 'request' };

var API_HOST_CACHED = process.env.API_HOST;
var GAE_SERVER_PORT_CACHED = process.env.GAE_SERVER_PORT;

process.env.API_HOST = 'API_HOST';
process.env.GAE_SERVER_PORT = 99;

httpRequestOverride = function(req) {
assert.deepEqual(req, mockRequest);
assert.equal(req.host, process.env.API_HOST);
assert.equal(req.port, process.env.GAE_SERVER_PORT);

done();

process.env.API_HOST = API_HOST_CACHED;
process.env.GAE_SERVER_PORT = GAE_SERVER_PORT_CACHED;

return new stream.Writable();
};
request.makeAuthorizedRequest_ = function(opts, callback) {
(callback.onAuthorized || callback)(null, mockRequest);
};
request.makeAuthorizedRequest_.getEnvironment = function() {
return {
GAE_DEV: true,
NO_CREDENTIALS: true
};
};
request.makeReq_('commit', {}, util.noop);
});

Expand All @@ -521,11 +578,14 @@ describe('Request', function() {
pbFakeMethodResponseDecode = function() {
done();
};
httpsRequestOverride = function(req, callback) {
var ws = new stream.Writable();
callback(ws);
ws.emit('end');
return ws;
httpsRequestOverride = function() {
var requestStream = new stream.PassThrough();
var responseStream = new stream.PassThrough();
setImmediate(function() {
requestStream.emit('response', responseStream);
responseStream.end();
});
return requestStream;
};
request.makeReq_('fakeMethod', util.noop);
});
Expand All @@ -535,6 +595,9 @@ describe('Request', function() {
request.createAuthorizedRequest_ = function(opts, callback) {
(callback.onAuthorized || callback)();
};
request.makeAuthorizedRequest_.getEnvironment = function() {
return {};
};
});

describe('commit', function() {
Expand Down

0 comments on commit a11254b

Please sign in to comment.