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

Commit

Permalink
All tests passing against live production kinesis
Browse files Browse the repository at this point in the history
  • Loading branch information
mhart committed Mar 25, 2018
1 parent 2221e7e commit 7d62e92
Show file tree
Hide file tree
Showing 14 changed files with 196 additions and 129 deletions.
42 changes: 33 additions & 9 deletions test/addTagsToStream.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,26 @@ describe('addTagsToStream', function() {
if (err) return done(err)
res.statusCode.should.equal(200)

assertInvalidArgument({
StreamName: helpers.testStream,
Tags: {d: '', e: '', f: '', g: '', h: '', i: ''},
}, 'Failed to add tags to stream ' + helpers.testStream + ' under account ' + helpers.awsAccountId +
' because a given stream cannot have more than 10 tags associated with it.', function(err) {
function addTagsUntilInvalid(i, cb) {
var tags = {}
for (j = 0; j < 10; j++) {
tags[i + j] = 'a'
}
if (i >= 40) {
return assertInvalidArgument({
StreamName: helpers.testStream,
Tags: tags,
}, 'Failed to add tags to stream ' + helpers.testStream + ' under account ' + helpers.awsAccountId +
' because a given stream cannot have more than 10 tags associated with it.', cb)
}
request(opts({StreamName: helpers.testStream, Tags: tags}), function(err, res) {
if (err) return cb(err)
res.statusCode.should.equal(200)
addTagsUntilInvalid(i + 10, cb)
})
}

addTagsUntilInvalid(0, function(err) {
if (err) return done(err)

request(helpers.opts('ListTagsForStream', {StreamName: helpers.testStream}), function(err, res) {
Expand All @@ -193,10 +208,19 @@ describe('addTagsToStream', function() {
res.body.Tags.should.containEql({Key: 'b', Value: 'ü0 _./=+-@'})
res.body.Tags.should.containEql({Key: 'c', Value: ''})

request(helpers.opts('RemoveTagsFromStream', {
StreamName: helpers.testStream,
TagKeys: ['a', 'ü0 _.', '/=+-@', 'b', 'c'],
}), done)
function removeAllTags(tagKeys, cb) {
if (!tagKeys.length) return cb()
request(helpers.opts('RemoveTagsFromStream', {
StreamName: helpers.testStream,
TagKeys: tagKeys.slice(0, 10),
}), function(err, res) {
if (err) return cb(err)
res.statusCode.should.equal(200)
removeAllTags(tagKeys.slice(10), cb)
})
}

removeAllTags(res.body.Tags.map(function(t) { return t.Key }), done)
})
})
})
Expand Down
84 changes: 53 additions & 31 deletions test/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ function assertBody(statusCode, contentType, body, done) {
} else {
res.headers.should.not.have.property('content-type')
}
if (typeof res.body != 'string') res.body = JSON.stringify(res.body)
res.headers['content-length'].should.equal(String(Buffer.byteLength(res.body, 'utf8')))
if (!Buffer.isBuffer(res.body)) {
if (typeof res.body != 'string') res.body = JSON.stringify(res.body)
res.body = Buffer.from(res.body, 'utf8')
}
res.headers['content-length'].should.equal(String(res.body.length))
res.headers['x-amzn-requestid'].should.match(uuidRegex)
new Buffer(res.headers['x-amz-id-2'], 'base64').length.should.be.within(72, 80)
new Buffer(res.headers['x-amz-id-2'], 'base64').length.should.be.within(64, 80)
done()
}
}
Expand Down Expand Up @@ -77,6 +80,16 @@ function assertUnknownDeprecated(done) {
}, done)
}

function assertUnknownCbor(done) {
return assertBody(400, 'application/x-amz-cbor-1.1', Buffer.concat([
Buffer.from('bf66', 'hex'),
Buffer.from('__type', 'utf8'),
Buffer.from('7819', 'hex'),
Buffer.from('UnknownOperationException', 'utf8'),
Buffer.from('ff', 'hex')
]), done)
}

function assertSerialization(done) {
return assertBody(400, 'application/x-amz-json-1.1', {__type: 'SerializationException'}, done)
}
Expand All @@ -88,6 +101,16 @@ function assertSerializationDeprecated(done) {
}, done)
}

function assertSerializationCbor(done) {
return assertBody(400, 'application/x-amz-cbor-1.1', Buffer.concat([
Buffer.from('bf66', 'hex'),
Buffer.from('__type', 'utf8'),
Buffer.from('76', 'hex'),
Buffer.from('SerializationException', 'utf8'),
Buffer.from('ff', 'hex')
]), done)
}

function assertMissing(done) {
return assertBody(400, 'application/x-amz-json-1.1', {
__type: 'MissingAuthenticationTokenException',
Expand Down Expand Up @@ -244,8 +267,8 @@ describe('kinesalite connections', function() {
})
}

it('should return MissingAuthenticationTokenException if POST with no auth', function(done) {
request({noSign: true}, assertMissingTokenXml(done))
it('should return CBOR UnknownOperationException if POST with no auth', function(done) {
request({noSign: true}, assertUnknownCbor(done))
})

it('should return AccessDeniedException if GET', function(done) {
Expand All @@ -260,57 +283,56 @@ describe('kinesalite connections', function() {
request({method: 'DELETE'}, assertAccessDeniedXml(done))
})

it('should return AccessDeniedException if POST with no body', function(done) {
request(assertAccessDeniedXml(done))
it('should return CBOR UnknownOperationException if POST with no body', function(done) {
request(assertUnknownCbor(done))
})

it('should return AccessDeniedException if body and no Content-Type', function(done) {
request({body: '{}'}, assertAccessDeniedXml(done))
})

it('should return AccessDeniedException if x-amz-json-1.0 Content-Type', function(done) {
request({headers: {'content-type': 'application/x-amz-json-1.0'}}, assertAccessDeniedXml(done))
it('should return CBOR UnknownOperationException if x-amz-json-1.0 Content-Type', function(done) {
request({headers: {'content-type': 'application/x-amz-json-1.0'}}, assertUnknownCbor(done))
})

it('should return AccessDeniedException if random Content-Type', function(done) {
request({headers: {'content-type': 'application/x-amz-json-1.1asdf'}}, assertAccessDeniedXml(done))
it('should return CBOR UnknownOperationException if random Content-Type', function(done) {
request({headers: {'content-type': 'application/x-amz-json-1.1asdf'}}, assertUnknownCbor(done))
})

it('should return AccessDeniedException if random target', function(done) {
request({headers: {'x-amz-target': 'Whatever'}}, assertAccessDeniedXml(done))
it('should return CBOR UnknownOperationException if random target', function(done) {
request({headers: {'x-amz-target': 'Whatever'}}, assertUnknownCbor(done))
})

it('should return AccessDeniedException if real service with empty action', function(done) {
request({headers: {'x-amz-target': 'Kinesis_20131202.'}}, assertAccessDeniedXml(done))
it('should return CBOR UnknownOperationException if real service with empty action', function(done) {
request({headers: {'x-amz-target': 'Kinesis_20131202.'}}, assertUnknownCbor(done))
})

it('should return InternalFailure if random action', function(done) {
request({headers: {'x-amz-target': 'Kinesis_20131202.Whatever'}}, assertInternalFailureXml(done))
it('should return CBOR UnknownOperationException if random action', function(done) {
request({headers: {'x-amz-target': 'Kinesis_20131202.Whatever'}}, assertUnknownCbor(done))
})

it('should return UnrecognizedClientException if random service with random action', function(done) {
request({headers: {'x-amz-target': 'Whatever.Whatever'}},
assertUnrecognizedClientXml('Whatever', 'Whatever', done))
it('should return CBOR UnknownOperationException if random service with random action', function(done) {
request({headers: {'x-amz-target': 'Whatever.Whatever'}}, assertUnknownCbor(done))
})

it('should return InternalFailure if incomplete action', function(done) {
request({headers: {'x-amz-target': 'Kinesis_20131202.ListStream'}}, assertInternalFailureXml(done))
it('should return CBOR UnknownOperationException if incomplete action', function(done) {
request({headers: {'x-amz-target': 'Kinesis_20131202.ListStream'}}, assertUnknownCbor(done))
})

it('should return UnknownOperationException if no Content-Type', function(done) {
request({headers: {'x-amz-target': 'Kinesis_20131202.ListStreams'}}, assertUnknownOperationXml(done))
it('should return CBOR SerializationException if no Content-Type', function(done) {
request({headers: {'x-amz-target': 'Kinesis_20131202.ListStreams'}}, assertSerializationCbor(done))
})

it('should return AccessDeniedException and set CORS if using Origin', function(done) {
it('should return CBOR UnknownOperationException and set CORS if using Origin', function(done) {
request({headers: {origin: 'whatever'}}, function(err, res) {
if (err) return done(err)
res.headers['access-control-allow-origin'].should.equal('*')
if (res.rawHeaders) {
res.headers['access-control-expose-headers'].should.equal('x-amz-request-id, x-amz-id-2')
res.headers['access-control-expose-headers'].should.equal('x-amzn-RequestId,x-amzn-ErrorType,x-amz-request-id,x-amz-id-2,x-amzn-ErrorMessage,Date')
} else {
res.headers['access-control-expose-headers'].should.equal('x-amz-request-id')
}
assertAccessDeniedXml(done)(err, res)
assertUnknownCbor(done)(err, res)
})
})

Expand Down Expand Up @@ -373,15 +395,15 @@ describe('kinesalite connections', function() {
request({headers: {'content-type': 'application/x-amz-json-1.1'}, noSign: true}, assertUnknown(done))
})

it('should return UnknownOperationException if no target and application/json', function(done) {
request({headers: {'content-type': 'application/json'}}, assertUnknownDeprecated(done))
it('should return CBOR UnknownOperationException if no target and application/json', function(done) {
request({headers: {'content-type': 'application/json'}}, assertUnknownCbor(done))
})

it('should return UnknownOperationException if valid target and application/json', function(done) {
it('should return CBOR SerializationException if valid target and application/json', function(done) {
request({headers: {
'content-type': 'application/json',
'x-amz-target': 'Kinesis_20131202.ListStreams',
}}, assertUnknownDeprecated(done))
}}, assertSerializationCbor(done))
})

it('should return SerializationException if no body', function(done) {
Expand Down
10 changes: 10 additions & 0 deletions test/createStream.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,18 @@ describe('createStream', function() {
if (err) return done(err)
res.statusCode.should.equal(200)

res.body.StreamDescription.StreamCreationTimestamp.should.be.above((createdAt / 1000) - 10)
res.body.StreamDescription.StreamCreationTimestamp.should.be.below((createdAt / 1000) + 10)
delete res.body.StreamDescription.StreamCreationTimestamp

res.body.should.eql({
StreamDescription: {
StreamStatus: 'CREATING',
StreamName: stream.StreamName,
StreamARN: 'arn:aws:kinesis:' + helpers.awsRegion + ':' + helpers.awsAccountId +
':stream/' + stream.StreamName,
RetentionPeriodHours: 24,
EncryptionType: 'NONE',
EnhancedMonitoring: [{ShardLevelMetrics: []}],
HasMoreShards: false,
Shards: [],
Expand Down Expand Up @@ -144,13 +149,18 @@ describe('createStream', function() {
delete res.body.StreamDescription.Shards[1].SequenceNumberRange.StartingSequenceNumber
delete res.body.StreamDescription.Shards[2].SequenceNumberRange.StartingSequenceNumber

res.body.StreamDescription.StreamCreationTimestamp.should.be.above((createdAt / 1000) - 10)
res.body.StreamDescription.StreamCreationTimestamp.should.be.below((createdAt / 1000) + 10)
delete res.body.StreamDescription.StreamCreationTimestamp

res.body.should.eql({
StreamDescription: {
StreamStatus: 'ACTIVE',
StreamName: stream.StreamName,
StreamARN: 'arn:aws:kinesis:' + helpers.awsRegion + ':' + helpers.awsAccountId +
':stream/' + stream.StreamName,
RetentionPeriodHours: 24,
EncryptionType: 'NONE',
EnhancedMonitoring: [{ShardLevelMetrics: []}],
HasMoreShards: false,
Shards: [{
Expand Down
13 changes: 7 additions & 6 deletions test/decreaseStreamRetentionPeriod.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,19 @@ describe('decreaseStreamRetentionPeriod', function() {
], done)
})

it('should return ValidationException for retention period greater than 168', function(done) {
assertValidation({StreamName: 'a', RetentionPeriodHours: 169}, [
'Value \'169\' at \'retentionPeriodHours\' failed to satisfy constraint: ' +
'Member must have value less than or equal to 168',
], done)
})

it('should return InvalidArgumentException for retention period less than 24', function(done) {
assertInvalidArgument({StreamName: helpers.testStream, RetentionPeriodHours: 23},
'Minimum allowed retention period is 24 hours. ' +
'Requested retention period (23 hours) is too short.', done)
})

it('should return InvalidArgumentException for retention period greater than 168', function(done) {
assertInvalidArgument({StreamName: helpers.testStream, RetentionPeriodHours: 169},
'Maximum allowed retention period is 168 hours. ' +
'Requested retention period (169 hours) is too long.', done)
})

it('should return InvalidArgumentException for retention period greater than current', function(done) {
assertInvalidArgument({StreamName: helpers.testStream, RetentionPeriodHours: 25},
'Requested retention period (25 hours) for stream ' + helpers.testStream +
Expand Down
6 changes: 6 additions & 0 deletions test/deleteStream.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ describe('deleteStream', function() {

it('should allow stream to be deleted while it is being created', function(done) {
this.timeout(100000)
var createTime = Date.now() / 1000
var stream = {StreamName: randomName(), ShardCount: 1}
request(helpers.opts('CreateStream', stream), function(err, res) {
if (err) return done(err)
Expand All @@ -77,13 +78,18 @@ describe('deleteStream', function() {
if (err) return done(err)
res.statusCode.should.equal(200)

res.body.StreamDescription.StreamCreationTimestamp.should.be.above(createTime - 10)
res.body.StreamDescription.StreamCreationTimestamp.should.be.below(createTime + 10)
delete res.body.StreamDescription.StreamCreationTimestamp

res.body.should.eql({
StreamDescription: {
StreamStatus: 'DELETING',
StreamName: stream.StreamName,
StreamARN: 'arn:aws:kinesis:' + helpers.awsRegion + ':' + helpers.awsAccountId +
':stream/' + stream.StreamName,
RetentionPeriodHours: 24,
EncryptionType: 'NONE',
EnhancedMonitoring: [{ShardLevelMetrics: []}],
HasMoreShards: false,
Shards: [],
Expand Down
5 changes: 5 additions & 0 deletions test/describeStream.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,18 @@ describe('describeStream', function() {
delete res.body.StreamDescription.Shards[1].SequenceNumberRange.StartingSequenceNumber
delete res.body.StreamDescription.Shards[2].SequenceNumberRange.StartingSequenceNumber

res.body.StreamDescription.StreamCreationTimestamp.should.be.above(new Date('2018-01-01') / 1000)
res.body.StreamDescription.StreamCreationTimestamp.should.be.below(new Date('2118-01-01') / 1000)
delete res.body.StreamDescription.StreamCreationTimestamp

res.body.should.eql({
StreamDescription: {
StreamStatus: 'ACTIVE',
StreamName: helpers.testStream,
StreamARN: 'arn:aws:kinesis:' + helpers.awsRegion + ':' + helpers.awsAccountId +
':stream/' + helpers.testStream,
RetentionPeriodHours: 24,
EncryptionType: 'NONE',
EnhancedMonitoring: [{ShardLevelMetrics: []}],
HasMoreShards: false,
Shards: [{
Expand Down
22 changes: 13 additions & 9 deletions test/getRecords.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ describe('getRecords', function() {
})

// Takes 5 minutes to run
it.skip('should return ExpiredIteratorException if ShardIterator has expired', function(done) {
it('should return ExpiredIteratorException if ShardIterator has expired', function(done) {
this.timeout(310000)
request(helpers.opts('GetShardIterator', {
StreamName: helpers.testStream,
Expand Down Expand Up @@ -87,7 +87,7 @@ describe('getRecords', function() {
})

// Takes 95 secs to run on production
it('should return ResourceNotFoundException if shard or stream does not exist', function(done) {
it.skip('should return ResourceNotFoundException if shard or stream does not exist', function(done) {
this.timeout(200000)
var stream = {StreamName: randomName(), ShardCount: 2}
request(helpers.opts('CreateStream', stream), function(err, res) {
Expand Down Expand Up @@ -150,15 +150,19 @@ describe('getRecords', function() {
' under account ' + helpers.awsAccountId + ' does not exist', function(err) {
if (err) return done(err)

request(opts({ShardIterator: shardIterator0}), function(err, res) {
if (err) return done(err)
res.statusCode.should.equal(200)
// TODO: This now causes an InternalFailure on production
// request(opts({ShardIterator: shardIterator0}), function(err, res) {
// if (err) return done(err)
// console.log(res.body)
// res.statusCode.should.equal(200)

res.body.Records.should.eql([])
helpers.assertShardIterator(res.body.NextShardIterator, stream.StreamName)
// res.body.Records.should.eql([])
// helpers.assertShardIterator(res.body.NextShardIterator, stream.StreamName)

request(helpers.opts('DeleteStream', {StreamName: stream.StreamName}), done)
})
// request(helpers.opts('DeleteStream', {StreamName: stream.StreamName}), done)
// })

request(helpers.opts('DeleteStream', {StreamName: stream.StreamName}), done)
})
})
})
Expand Down
Loading

0 comments on commit 7d62e92

Please sign in to comment.