Merge pull request #2456 from serverless/add-additional-api-gateway-tests-for-lambda-proxy-integration

Add additional API Gateway tests for lambda proxy integration
This commit is contained in:
Philipp Muens 2016-10-19 16:34:21 +02:00 committed by GitHub
commit afbf7a1b20
11 changed files with 345 additions and 3 deletions

View File

@ -14,6 +14,9 @@ require('./aws/api-gateway/integration-lambda/cors/tests');
require('./aws/api-gateway/integration-lambda/api-keys/tests');
// Integration: Lambda Proxy
require('./aws/api-gateway/integration-lambda-proxy/simple-api/tests');
require('./aws/api-gateway/integration-lambda-proxy/custom-authorizers/tests');
require('./aws/api-gateway/integration-lambda-proxy/cors/tests');
require('./aws/api-gateway/integration-lambda-proxy/api-keys/tests');
// Schedule
require('./aws/schedule/multiple-schedules-multiple-functions/tests');

View File

@ -0,0 +1,13 @@
'use strict';
module.exports.hello = (event, context, callback) => {
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'Hello from API Gateway!',
event,
}),
};
callback(null, response);
};

View File

@ -0,0 +1,16 @@
service: aws-nodejs # NOTE: update this with your service name
provider:
name: aws
runtime: nodejs4.3
apiKeys:
- WillBeReplacedBeforeDeployment
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: GET
private: true

View File

@ -0,0 +1,85 @@
'use strict';
const path = require('path');
const expect = require('chai').expect;
const BbPromise = require('bluebird');
const execSync = require('child_process').execSync;
const AWS = require('aws-sdk');
const _ = require('lodash');
const fetch = require('node-fetch');
const fse = require('fs-extra');
const crypto = require('crypto');
const Utils = require('../../../../../utils/index');
const CF = new AWS.CloudFormation({ region: 'us-east-1' });
const APIG = new AWS.APIGateway({ region: 'us-east-1' });
BbPromise.promisifyAll(CF, { suffix: 'Promised' });
BbPromise.promisifyAll(APIG, { suffix: 'Promised' });
describe('AWS - API Gateway (Integration: Lambda Proxy): API keys test', function () {
this.timeout(0);
let stackName;
let endpoint;
let apiKey;
before(() => {
stackName = Utils.createTestService('aws-nodejs', path.join(__dirname, 'service'));
// replace name of the API key with something unique
const serverlessYmlFilePath = path.join(process.cwd(), 'serverless.yml');
let serverlessYmlFileContent = fse.readFileSync(serverlessYmlFilePath).toString();
const apiKeyName = crypto.randomBytes(8).toString('hex');
serverlessYmlFileContent = serverlessYmlFileContent
.replace(/WillBeReplacedBeforeDeployment/, apiKeyName);
fse.writeFileSync(serverlessYmlFilePath, serverlessYmlFileContent);
Utils.deployService();
});
it('should expose the endpoint(s) in the CloudFormation Outputs', () =>
CF.describeStacksPromised({ StackName: stackName })
.then((result) => _.find(result.Stacks[0].Outputs,
{ OutputKey: 'ServiceEndpoint' }).OutputValue)
.then((endpointOutput) => {
endpoint = endpointOutput.match(/https:\/\/.+\.execute-api\..+\.amazonaws\.com.+/)[0];
endpoint = `${endpoint}/hello`;
})
);
it('should expose the API key(s) with its values when running the info command', () => {
const info = execSync(`${Utils.serverlessExec} info`);
const stringifiedOutput = (new Buffer(info, 'base64').toString());
// some regex magic to extract the first API key value from the info output
apiKey = stringifiedOutput.match(/(api keys:\n)(\s*)(.+):(\s*)(.+)/)[5];
expect(apiKey.length).to.be.above(0);
});
it('should reject a request with an invalid API Key', () =>
fetch(endpoint)
.then((response) => {
expect(response.status).to.equal(403);
})
);
it('should succeed if correct API key is given', () =>
fetch(endpoint, { headers: { 'x-api-key': apiKey } })
.then(response => response.json())
.then((json) => {
expect(json.message).to.equal('Hello from API Gateway!');
expect(json.event.requestContext.identity.apiKey).to.equal(apiKey);
expect(json.event.headers['x-api-key']).to.equal(apiKey);
})
);
after(() => {
Utils.removeService();
});
});

View File

@ -0,0 +1,16 @@
'use strict';
module.exports.hello = (event, context, callback) => {
const response = {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify({
message: 'Hello from API Gateway!',
input: event,
}),
};
callback(null, response);
};

View File

@ -0,0 +1,26 @@
service: aws-nodejs # NOTE: update this with your service name
provider:
name: aws
runtime: nodejs4.3
functions:
hello:
handler: handler.hello
events:
- http:
method: GET
path: simple-cors
cors: true
- http:
method: GET
path: complex-cors
cors:
origins:
- '*'
headers:
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token

View File

@ -0,0 +1,62 @@
'use strict';
const path = require('path');
const expect = require('chai').expect;
const BbPromise = require('bluebird');
const AWS = require('aws-sdk');
const _ = require('lodash');
const fetch = require('node-fetch');
const Utils = require('../../../../../utils/index');
const CF = new AWS.CloudFormation({ region: 'us-east-1' });
BbPromise.promisifyAll(CF, { suffix: 'Promised' });
describe('AWS - API Gateway (Integration: Lambda Proxy): CORS test', function () {
this.timeout(0);
let stackName;
let endpointBase;
before(() => {
stackName = Utils.createTestService('aws-nodejs', path.join(__dirname, 'service'));
Utils.deployService();
});
it('should expose the endpoint(s) in the CloudFormation Outputs', () =>
CF.describeStacksPromised({ StackName: stackName })
.then((result) => _.find(result.Stacks[0].Outputs,
{ OutputKey: 'ServiceEndpoint' }).OutputValue)
.then((endpointOutput) => {
endpointBase = endpointOutput.match(/https:\/\/.+\.execute-api\..+\.amazonaws\.com.+/)[0];
})
);
it('should setup CORS support with simple string config', () =>
fetch(`${endpointBase}/simple-cors`, { method: 'OPTIONS' })
.then((response) => {
const headers = response.headers;
expect(headers.get('access-control-allow-headers'))
.to.equal('Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token');
expect(headers.get('access-control-allow-methods')).to.equal('OPTIONS,GET');
expect(headers.get('access-control-allow-origin')).to.equal('*');
})
);
it('should setup CORS support with complex object config', () =>
fetch(`${endpointBase}/complex-cors`, { method: 'OPTIONS' })
.then((response) => {
const headers = response.headers;
expect(headers.get('access-control-allow-headers'))
.to.equal('Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token');
expect(headers.get('access-control-allow-methods')).to.equal('OPTIONS,GET');
expect(headers.get('access-control-allow-origin')).to.equal('*');
})
);
after(() => {
Utils.removeService();
});
});

View File

@ -0,0 +1,45 @@
'use strict';
const generatePolicy = (principalId, effect, resource) => {
const authResponse = {};
authResponse.principalId = principalId;
if (effect && resource) {
const policyDocument = {};
policyDocument.Version = '2012-10-17';
policyDocument.Statement = [];
const statementOne = {};
statementOne.Action = 'execute-api:Invoke';
statementOne.Effect = effect;
statementOne.Resource = resource;
policyDocument.Statement[0] = statementOne;
authResponse.policyDocument = policyDocument;
}
return authResponse;
};
// protected function
module.exports.hello = (event, context, callback) => {
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'Successfully authorized!',
event,
}),
};
callback(null, response);
};
// auth function
module.exports.auth = (event, context) => {
const token = event.authorizationToken.split(' ');
if (token[0] === 'Bearer' && token[1] === 'ShouldBeAuthorized') {
context.succeed(generatePolicy('SomeRandomId', 'Allow', '*'));
}
context.fail('Unauthorized');
};

View File

@ -0,0 +1,16 @@
service: aws-nodejs # NOTE: update this with your service name
provider:
name: aws
runtime: nodejs4.3
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: GET
authorizer: auth
auth:
handler: handler.auth

View File

@ -0,0 +1,63 @@
'use strict';
const path = require('path');
const expect = require('chai').expect;
const BbPromise = require('bluebird');
const AWS = require('aws-sdk');
const _ = require('lodash');
const fetch = require('node-fetch');
const Utils = require('../../../../../utils/index');
const CF = new AWS.CloudFormation({ region: 'us-east-1' });
BbPromise.promisifyAll(CF, { suffix: 'Promised' });
describe('AWS - API Gateway (Integration: Lambda Proxy): Custom authorizers test', function () {
this.timeout(0);
let stackName;
let endpoint;
before(() => {
stackName = Utils.createTestService('aws-nodejs', path.join(__dirname, 'service'));
Utils.deployService();
});
it('should expose the endpoint(s) in the CloudFormation Outputs', () =>
CF.describeStacksPromised({ StackName: stackName })
.then((result) => _.find(result.Stacks[0].Outputs,
{ OutputKey: 'ServiceEndpoint' }).OutputValue)
.then((endpointOutput) => {
endpoint = endpointOutput.match(/https:\/\/.+\.execute-api\..+\.amazonaws\.com.+/)[0];
endpoint = `${endpoint}/hello`;
})
);
it('should reject requests without authorization', () =>
fetch(endpoint)
.then((response) => {
expect(response.status).to.equal(401);
})
);
it('should reject requests with wrong authorization', () =>
fetch(endpoint, { headers: { Authorization: 'Bearer ShouldNotBeAuthorized' } })
.then((response) => {
expect(response.status).to.equal(401);
})
);
it('should authorize requests with correct authorization', () =>
fetch(endpoint, { headers: { Authorization: 'Bearer ShouldBeAuthorized' } })
.then(response => response.json())
.then((json) => {
expect(json.message).to.equal('Successfully authorized!');
expect(json.event.requestContext.authorizer.principalId).to.equal('SomeRandomId');
expect(json.event.headers.Authorization).to.equal('Bearer ShouldBeAuthorized');
})
);
after(() => {
Utils.removeService();
});
});

View File

@ -10,7 +10,4 @@ module.exports.hello = (event, context, callback) => {
};
callback(null, response);
// Use this code if you don't use the http event with the LAMBDA-PROXY integration
// callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event });
};