aws-sdk 2.0.1 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc +20 -0
- package/.gitignore +10 -0
- package/.travis.yml +20 -0
- package/.yardopts +20 -0
- package/.yardopts_guide +21 -0
- package/Gemfile +16 -0
- package/Gemfile.lock +34 -0
- package/README.md +5 -6
- package/Rakefile +14 -0
- package/UPGRADING.md +9 -4
- package/configuration.sample +5 -0
- package/dist/BUNDLE_LICENSE.txt +96 -0
- package/dist/aws-sdk.js +9594 -0
- package/dist/aws-sdk.min.js +21 -0
- package/dist-tools/.eslintrc +10 -0
- package/dist-tools/browser-builder.js +142 -0
- package/dist-tools/strategies/cache.js +68 -0
- package/dist-tools/strategies/default.js +165 -0
- package/dist-tools/test/browser-builder.mocha.spec.coffee +182 -0
- package/dist-tools/test/helpers.coffee +16 -0
- package/doc-src/guide/browser-building.md +93 -0
- package/doc-src/guide/browser-configuring-wif.md +287 -0
- package/doc-src/guide/browser-configuring.md +218 -0
- package/doc-src/guide/browser-examples.md +220 -0
- package/doc-src/guide/browser-intro.md +46 -0
- package/doc-src/guide/browser-making-requests.md +279 -0
- package/doc-src/guide/browser-services.md +75 -0
- package/doc-src/guide/index.md +41 -0
- package/doc-src/guide/node-configuring.md +272 -0
- package/doc-src/guide/node-examples.md +341 -0
- package/doc-src/guide/node-intro.md +32 -0
- package/doc-src/guide/node-making-requests.md +309 -0
- package/doc-src/guide/node-services.md +159 -0
- package/doc-src/templates/api-versions/model_documentor.rb +366 -0
- package/doc-src/templates/api-versions/plugin.rb +230 -0
- package/doc-src/templates/api-versions/templates/default/class/html/setup.rb +9 -0
- package/doc-src/templates/api-versions/templates/default/class/html/waiter_details_list.erb +7 -0
- package/doc-src/templates/api-versions/templates/default/class/html/waiter_summary.erb +7 -0
- package/doc-src/templates/api-versions/templates/default/docstring/html/experimental.erb +4 -0
- package/doc-src/templates/api-versions/templates/default/docstring/setup.rb +9 -0
- package/doc-src/templates/api-versions/templates/default/fulldoc/html/css/common.css +6 -0
- package/doc-src/templates/api-versions/templates/default/fulldoc/html/setup.rb +62 -0
- package/doc-src/templates/api-versions/templates/default/layout/html/services.erb +10 -0
- package/doc-src/templates/api-versions/templates/default/layout/html/setup.rb +28 -0
- package/doc-src/templates/api-versions/templates/default/module/html/box_info.erb +45 -0
- package/doc-src/templates/api-versions/templates/default/module/html/children.erb +8 -0
- package/doc-src/templates/api-versions/templates/default/tags/setup.rb +3 -0
- package/doc-src/templates/api-versions/templates/default/waiter_details/html/method_signature.erb +3 -0
- package/doc-src/templates/api-versions/templates/default/waiter_details/html/setup.rb +5 -0
- package/doc-src/templates/default/layout/html/footer.erb +31 -0
- package/doc-src/templates/default/layout/html/layout.erb +23 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/css/highlight.github.css +127 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/css/style.css +1192 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/img/logo.png +0 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/js/app.js +33 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/js/highlight.pack.js +27 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/js/sphinx/AUTHORS +55 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/js/sphinx/LICENSE +25 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/js/sphinx/doctools.js +247 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/js/sphinx/file.png +0 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/js/sphinx/searchtools.js +568 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/js/underscore.js +23 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/search.erb +29 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/search_index.erb +1 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/setup.rb +75 -0
- package/doc-src/templates/flasky_sphinx_guide/layout/html/layout.erb +93 -0
- package/doc-src/templates/flasky_sphinx_guide/layout/html/setup.rb +9 -0
- package/doc-src/templates/flasky_sphinx_guide/layout/html/sidebar.erb +45 -0
- package/doc-src/templates/flasky_sphinx_guide/onefile/html/layout.erb +51 -0
- package/doc-src/templates/flasky_sphinx_guide/onefile/html/setup.rb +1 -0
- package/eslint-rules/no-require-in-service.js +10 -0
- package/features/autoscaling/autoscaling.feature +21 -0
- package/features/autoscaling/step_definitions/autoscaling.js +49 -0
- package/features/cloudformation/cloudformation.feature +22 -0
- package/features/cloudformation/step_definitions/cloudformation.js +26 -0
- package/features/cloudfront/cloudfront.feature +28 -0
- package/features/cloudfront/step_definitions/cloudfront-latest.js +54 -0
- package/features/cloudfront/step_definitions/cloudfront.js +21 -0
- package/features/cloudsearch/cloudsearch.feature +34 -0
- package/features/cloudsearch/step_definitions/cloudsearch.js +42 -0
- package/features/cloudtrail/cloudtrail.feature +17 -0
- package/features/cloudtrail/step_definitions/cloudtrail.js +14 -0
- package/features/cloudwatch/cloudwatch.feature +15 -0
- package/features/cloudwatch/step_definitions/cloudwatch.js +48 -0
- package/features/datapipeline/datapipeline.feature +23 -0
- package/features/datapipeline/step_definitions/datapipeline.js +79 -0
- package/features/directconnect/directconnect.feature +20 -0
- package/features/directconnect/step_definitions/directconnect.js +44 -0
- package/features/dynamodb/crc32.feature +18 -0
- package/features/dynamodb/step_definitions/dynamodb.js +154 -0
- package/features/dynamodb/tables.feature +50 -0
- package/features/ec2/ec2.feature +28 -0
- package/features/ec2/step_definitions/ec2.js +65 -0
- package/features/elasticache/elasticache.feature +20 -0
- package/features/elasticache/step_definitions/elasticache.js +34 -0
- package/features/elasticbeanstalk/elasticbeanstalk.feature +22 -0
- package/features/elasticbeanstalk/step_definitions/elasticbeanstalk.js +38 -0
- package/features/elastictranscoder/elastictranscoder.feature +24 -0
- package/features/elastictranscoder/step_definitions/elastictranscoder.js +56 -0
- package/features/elb/elb.feature +19 -0
- package/features/elb/step_definitions/elb.js +37 -0
- package/features/emr/emr.feature +16 -0
- package/features/emr/step_definitions/emr.js +45 -0
- package/features/extra/assertions.js +29 -0
- package/features/extra/dummy.feature +0 -0
- package/features/extra/fixtures/testfile.txt +1 -0
- package/features/extra/helpers.js +113 -0
- package/features/extra/hooks.js +107 -0
- package/features/extra/world.js +12 -0
- package/features/glacier/glacier.feature +47 -0
- package/features/glacier/step_definitions/glacier.js +112 -0
- package/features/iam/iam.feature +24 -0
- package/features/iam/step_definitions/iam.js +66 -0
- package/features/importexport/importexport.feature +53 -0
- package/features/importexport/step_definitions/importexport.js +42 -0
- package/features/kinesis/kinesis.feature +9 -0
- package/features/kinesis/step_definitions/kinesis.js +10 -0
- package/features/opsworks/opsworks.feature +26 -0
- package/features/opsworks/step_definitions/opsworks.js +42 -0
- package/features/rds/rds.feature +32 -0
- package/features/rds/step_definitions/rds.js +72 -0
- package/features/redshift/redshift.feature +20 -0
- package/features/redshift/step_definitions/redshift.js +33 -0
- package/features/route53/route53.feature +41 -0
- package/features/route53/step_definitions/route53.js +97 -0
- package/features/s3/buckets.feature +40 -0
- package/features/s3/objects.feature +122 -0
- package/features/s3/step_definitions/buckets.js +136 -0
- package/features/s3/step_definitions/hooks.js +39 -0
- package/features/s3/step_definitions/objects.js +204 -0
- package/features/s3/step_definitions/proxy.js +44 -0
- package/features/ses/ses.feature +20 -0
- package/features/ses/step_definitions/ses.js +22 -0
- package/features/simpledb/simpledb.feature +29 -0
- package/features/simpledb/step_definitions/simpledb.js +46 -0
- package/features/sns/sns.feature +15 -0
- package/features/sns/step_definitions/sns.js +33 -0
- package/features/sqs/messages.feature +21 -0
- package/features/sqs/queues.feature +18 -0
- package/features/sqs/step_definitions/messages.js +46 -0
- package/features/sqs/step_definitions/queues.js +33 -0
- package/features/sqs/step_definitions/sqs.js +7 -0
- package/features/storagegateway/step_definitions/storagegateway.js +16 -0
- package/features/storagegateway/storagegateway.feature +13 -0
- package/features/sts/step_definitions/sts.js +35 -0
- package/features/sts/sts.feature +29 -0
- package/features/support/step_definitions/support.js +35 -0
- package/features/support/support.feature +18 -0
- package/features/swf/step_definitions/swf.js +38 -0
- package/features/swf/swf.feature +15 -0
- package/index.js +2 -0
- package/lib/core.js +2 -2
- package/lib/credentials/shared_ini_file_credentials.js +0 -1
- package/lib/event_listeners.js +13 -1
- package/lib/http/node.js +19 -30
- package/lib/model/resource_waiter.js +0 -4
- package/lib/model/shape.js +2 -1
- package/lib/protocol/rest_xml.js +1 -1
- package/lib/region_config.js +31 -0
- package/lib/region_config.json +56 -0
- package/lib/request.js +37 -45
- package/lib/sequential_executor.js +17 -34
- package/lib/service.js +17 -44
- package/lib/services/cloudsearchdomain.js +69 -0
- package/lib/services/route53.js +0 -12
- package/lib/services/s3.js +3 -19
- package/lib/signers/v4.js +2 -1
- package/lib/util.js +28 -3
- package/package.json +3 -3
- package/scripts/console +11 -3
- package/scripts/coverage +126 -0
- package/tasks/apis.rake +122 -0
- package/tasks/browser.rake +89 -0
- package/tasks/docs.rake +36 -0
- package/tasks/lib/cucumber_generator.rb +40 -0
- package/tasks/util.rake +33 -0
- package/test/browser/js/jasmine-1.3.1.js +2600 -0
- package/test/browser/js/jasmine-html.js +681 -0
- package/test/browser/runner.html +109 -0
- package/test/browser/runner.js +92 -0
- package/test/browser/sample/appinfo.sample.js +15 -0
- package/test/browser/sample/console.html +429 -0
- package/test/browser/sample/css/smoothness/images/animated-overlay.gif +0 -0
- package/test/browser/sample/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- package/test/browser/sample/css/smoothness/jquery-ui-1.10.1.custom.css +1175 -0
- package/test/browser/sample/css/smoothness/jquery-ui-1.10.1.custom.min.css +5 -0
- package/test/browser/sample/img/loading.gif +0 -0
- package/test/browser/sample/js/jquery-1.9.1.js +9597 -0
- package/test/browser/sample/js/jquery-ui-1.10.1.custom.js +14903 -0
- package/test/browser/sample/js/jquery-ui-1.10.1.custom.min.js +6 -0
- package/test/browser/sample/s3upload.html +111 -0
- package/test/browser.spec.coffee +207 -0
- package/test/config.spec.coffee +202 -0
- package/test/credential_provider_chain.spec.coffee +90 -0
- package/test/credentials.spec.coffee +452 -0
- package/test/endpoint.spec.coffee +80 -0
- package/test/event_listeners.spec.coffee +493 -0
- package/test/helpers.coffee +150 -0
- package/test/http_request.spec.coffee +55 -0
- package/test/json/builder.spec.coffee +129 -0
- package/test/json/parser.spec.coffee +108 -0
- package/test/metadata_service.spec.coffee +54 -0
- package/test/model/api.spec.coffee +67 -0
- package/test/model/shape.spec.coffee +23 -0
- package/test/node_http_client.spec.coffee +40 -0
- package/test/param_validator.spec.coffee +456 -0
- package/test/protocol/json.spec.coffee +167 -0
- package/test/protocol/query.spec.coffee +191 -0
- package/test/protocol/rest.spec.coffee +237 -0
- package/test/protocol/rest_json.spec.coffee +255 -0
- package/test/protocol/rest_xml.spec.coffee +329 -0
- package/test/query/query_param_serializer.spec.coffee +327 -0
- package/test/region_config.spec.coffee +50 -0
- package/test/request.spec.coffee +316 -0
- package/test/resource_waiter.spec.coffee +89 -0
- package/test/response.spec.coffee +81 -0
- package/test/sequential_executor.spec.coffee +118 -0
- package/test/service.spec.coffee +230 -0
- package/test/services/cloudfront.spec.coffee +44 -0
- package/test/services/cloudsearchdomain.spec.coffee +23 -0
- package/test/services/dynamodb.spec.coffee +32 -0
- package/test/services/ec2.spec.coffee +78 -0
- package/test/services/elastictranscoder.spec.coffee +43 -0
- package/test/services/glacier.spec.coffee +61 -0
- package/test/services/rds.spec.coffee +38 -0
- package/test/services/route53.spec.coffee +77 -0
- package/test/services/s3.spec.coffee +538 -0
- package/test/services/simpledb.spec.coffee +12 -0
- package/test/services/sqs.spec.coffee +130 -0
- package/test/services/sts.spec.coffee +72 -0
- package/test/services/swf.spec.coffee +6 -0
- package/test/signers/presign.spec.coffee +36 -0
- package/test/signers/s3.spec.coffee +297 -0
- package/test/signers/v2.spec.coffee +68 -0
- package/test/signers/v4.spec.coffee +135 -0
- package/test/util.spec.coffee +510 -0
- package/test/xml/builder.spec.coffee +529 -0
- package/test/xml/parser.spec.coffee +587 -0
- package/lib/services/simpledb.js +0 -15
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module.exports = function() {
|
|
2
|
+
this.Before("@elastictranscoder", function (callback) {
|
|
3
|
+
this.iam = new this.AWS.IAM();
|
|
4
|
+
this.s3 = new this.AWS.S3();
|
|
5
|
+
this.service = new this.AWS.ElasticTranscoder();
|
|
6
|
+
callback();
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
this.Given(/^I create an Elastic Transcoder pipeline with name prefix "([^"]*)"$/, function(prefix, callback) {
|
|
10
|
+
this.pipelineName = this.uniqueName(prefix);
|
|
11
|
+
var params = {
|
|
12
|
+
Name: this.pipelineName,
|
|
13
|
+
InputBucket: this.bucket,
|
|
14
|
+
OutputBucket: this.bucket,
|
|
15
|
+
Role: this.iamRoleArn,
|
|
16
|
+
Notifications: {"Progressing":"","Completed":"","Warning":"","Error":""}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
var world = this;
|
|
20
|
+
var next = function() {
|
|
21
|
+
if (world.data) world.pipelineId = world.data.Pipeline.Id;
|
|
22
|
+
callback();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
this.request(null, 'createPipeline', params, next, false);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
this.Given(/^I list pipelines$/, function(callback) {
|
|
29
|
+
this.request(null, 'listPipelines', {}, callback);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
this.Then(/^the list should contain the pipeline$/, function(callback) {
|
|
33
|
+
var id = this.pipelineId;
|
|
34
|
+
this.assert.contains(this.data.Pipelines, function (pipeline) {
|
|
35
|
+
return pipeline.Id === id;
|
|
36
|
+
});
|
|
37
|
+
callback();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
this.Then(/^I pause the pipeline$/, function(callback) {
|
|
41
|
+
this.request(null, 'updatePipelineStatus', {Id:this.pipelineId, Status: 'Paused'}, callback);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
this.Then(/^I read the pipeline$/, function(callback) {
|
|
45
|
+
this.request(null, 'readPipeline', {Id: this.pipelineId}, callback);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
this.Then(/^the pipeline status should be "([^"]*)"$/, function(status, callback) {
|
|
49
|
+
this.assert.equal(this.data.Pipeline.Status, status);
|
|
50
|
+
callback();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
this.Then(/^I delete the pipeline$/, function(callback) {
|
|
54
|
+
this.request(null, 'deletePipeline', {Id: this.pipelineId}, callback);
|
|
55
|
+
});
|
|
56
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# language: en
|
|
2
|
+
@elb
|
|
3
|
+
Feature: Elastic Load Balancing
|
|
4
|
+
|
|
5
|
+
I want to use Elastic Load Balancing
|
|
6
|
+
|
|
7
|
+
Scenario: Creating load balancers
|
|
8
|
+
Given I create a load balancer with name prefix "aws-sdk-js"
|
|
9
|
+
And I describe load balancers with the load balancer name
|
|
10
|
+
Then the load balancer should be in the list
|
|
11
|
+
And I delete the load balancer
|
|
12
|
+
|
|
13
|
+
Scenario: Error handling
|
|
14
|
+
Given I create a load balancer with name prefix "verylongelasticloadbalancername"
|
|
15
|
+
Then the error code should be "ValidationError"
|
|
16
|
+
Then the error message should be:
|
|
17
|
+
"""
|
|
18
|
+
LoadBalancer name cannot be longer than 32 characters
|
|
19
|
+
"""
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module.exports = function() {
|
|
2
|
+
this.Before("@elb", function (callback) {
|
|
3
|
+
this.service = new this.AWS.ELB();
|
|
4
|
+
callback();
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
this.Given(/^I create a load balancer with name prefix "([^"]*)"$/, function(prefix, callback) {
|
|
8
|
+
this.loadBalancerName = prefix + '-' + new Date().getTime();
|
|
9
|
+
|
|
10
|
+
var params = {
|
|
11
|
+
LoadBalancerName: this.loadBalancerName,
|
|
12
|
+
Listeners: [{Protocol: 'TCP', LoadBalancerPort: 80, InstancePort: 80}],
|
|
13
|
+
AvailabilityZones: ['us-east-1a']
|
|
14
|
+
};
|
|
15
|
+
this.request(null, 'createLoadBalancer', params, callback, false);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
this.Given(/^I describe load balancers with the load balancer name$/, function(callback) {
|
|
19
|
+
var params = {LoadBalancerNames: [this.loadBalancerName]};
|
|
20
|
+
this.request(null, 'describeLoadBalancers', params, callback);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
this.Then(/^the load balancer should be in the list$/, function(callback) {
|
|
24
|
+
var name = this.data.LoadBalancerDescriptions[0].LoadBalancerName;
|
|
25
|
+
this.assert.equal(name, this.loadBalancerName);
|
|
26
|
+
callback();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
this.Then(/^I delete the load balancer$/, function(callback) {
|
|
30
|
+
var params = {LoadBalancerName: this.loadBalancerName};
|
|
31
|
+
this.request(null, 'deleteLoadBalancer', params, callback);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
this.Given(/^I try to create a load balancer with no name$/, function(callback) {
|
|
35
|
+
this.request(null, 'createLoadBalancer', {}, callback);
|
|
36
|
+
});
|
|
37
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# language: en
|
|
2
|
+
@emr
|
|
3
|
+
Feature: Amazon Elastic MapReduce
|
|
4
|
+
|
|
5
|
+
I want to use Amazon Elastic MapReduce
|
|
6
|
+
|
|
7
|
+
Scenario: Running a job flow
|
|
8
|
+
Given I run an EMR job flow with name prefix "aws-sdk-js-integration"
|
|
9
|
+
Then I should store the job flow ID
|
|
10
|
+
And when I describe the EMR job flows
|
|
11
|
+
Then the list should contain the job flow ID
|
|
12
|
+
And I terminate the job flow
|
|
13
|
+
|
|
14
|
+
Scenario: Error handling
|
|
15
|
+
Given I run an EMR job flow with invalid parameters
|
|
16
|
+
Then the error code should be "ValidationException"
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module.exports = function() {
|
|
2
|
+
this.Before("@emr", function (callback) {
|
|
3
|
+
this.service = new this.AWS.EMR();
|
|
4
|
+
callback();
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
this.Given(/^I run an EMR job flow with name prefix "([^"]*)"$/, function(prefix, callback) {
|
|
8
|
+
var params = {
|
|
9
|
+
Name: this.uniqueName(prefix),
|
|
10
|
+
Instances: {
|
|
11
|
+
MasterInstanceType: 'm1.small',
|
|
12
|
+
SlaveInstanceType: 'm1.small',
|
|
13
|
+
InstanceCount: 1,
|
|
14
|
+
TerminationProtected: false
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
this.request(null, 'runJobFlow', params, callback);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
this.Then(/^I should store the job flow ID$/, function(callback) {
|
|
21
|
+
this.jobFlowId = this.data.JobFlowId;
|
|
22
|
+
callback();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
this.Then(/^when I describe the EMR job flows$/, function(callback) {
|
|
26
|
+
this.request(null, 'describeJobFlows', {}, callback);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
this.Then(/^the list should contain the job flow ID$/, function(callback) {
|
|
30
|
+
var jobFlowId = this.jobFlowId;
|
|
31
|
+
this.assert.contains(this.data.JobFlows, function(job) {
|
|
32
|
+
return job.JobFlowId === jobFlowId;
|
|
33
|
+
});
|
|
34
|
+
callback();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
this.Then(/^I terminate the job flow$/, function(callback) {
|
|
38
|
+
this.request(null, 'terminateJobFlows', {JobFlowIds: [this.jobFlowId]}, callback);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
this.Given(/^I run an EMR job flow with invalid parameters$/, function(callback) {
|
|
42
|
+
var params = {Name: '', Instances: {MasterInstanceType: 'invalid'}};
|
|
43
|
+
this.request(null, 'runJobFlow', params, callback, false);
|
|
44
|
+
});
|
|
45
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
var assert = require('assert');
|
|
2
|
+
|
|
3
|
+
assert.match = function assertMatches(string, matcher, message) {
|
|
4
|
+
assert.ok(string.match(matcher), message ||
|
|
5
|
+
'Expected ' + string + ' to match ' + matcher);
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
assert.contains = function assertContains(list, matcher, message) {
|
|
9
|
+
var found = false;
|
|
10
|
+
for (var i in list) {
|
|
11
|
+
if (!list.hasOwnProperty(i)) continue;
|
|
12
|
+
if (typeof matcher === 'function') {
|
|
13
|
+
found = matcher(list[i]);
|
|
14
|
+
} else {
|
|
15
|
+
found = (list[i] === matcher);
|
|
16
|
+
}
|
|
17
|
+
if (found) return;
|
|
18
|
+
}
|
|
19
|
+
assert.fail(list, matcher, message, 'does not contain');
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
assert.compare = function assertComparison(actual, operator, expected, message) {
|
|
23
|
+
var compare = actual + ' ' + operator + ' ' + expected;
|
|
24
|
+
assert.ok(eval(compare), message || compare);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = {
|
|
28
|
+
assert: assert
|
|
29
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
CONTENTS OF FILE
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
|
|
3
|
+
assert: require('./assertions').assert,
|
|
4
|
+
|
|
5
|
+
uniqueName: function uniqueName(base) {
|
|
6
|
+
if (base === "") return "";
|
|
7
|
+
return base + '-' + new Date().getTime();
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Call this function with a block that will be executed multiple times
|
|
12
|
+
* to deal with eventually consistent conditions.
|
|
13
|
+
*
|
|
14
|
+
* this.When(/^I something is eventually consistent$/, function(callback) {
|
|
15
|
+
* this.eventually(callback, function(next) {
|
|
16
|
+
* doSomething(function(response) {
|
|
17
|
+
* if (response != notWhatIExpect) {
|
|
18
|
+
* next.fail();
|
|
19
|
+
* } else {
|
|
20
|
+
* next();
|
|
21
|
+
* }
|
|
22
|
+
* });
|
|
23
|
+
* });
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* You can pass in a few options after the function:
|
|
27
|
+
*
|
|
28
|
+
* delay: The number of milliseconds to delay before retrying.
|
|
29
|
+
* backoff: Add this number of milliseconds to the delay between each attempt.
|
|
30
|
+
* maxTime: Maximum duration of milliseconds to wait for success.
|
|
31
|
+
*/
|
|
32
|
+
eventually: function eventually(callback, block, options) {
|
|
33
|
+
|
|
34
|
+
if (!options) options = {};
|
|
35
|
+
if (!options.delay) options.delay = 0;
|
|
36
|
+
if (!options.backoff) options.backoff = 500;
|
|
37
|
+
if (!options.maxTime) options.maxTime = 5;
|
|
38
|
+
|
|
39
|
+
var delay = options.delay;
|
|
40
|
+
var started = this.AWS.util.date.getDate();
|
|
41
|
+
|
|
42
|
+
var self = this;
|
|
43
|
+
var retry = function() { callback(); };
|
|
44
|
+
retry.fail = function(err) {
|
|
45
|
+
var now = self.AWS.util.date.getDate();
|
|
46
|
+
if (now - started < options.maxTime * 1000) {
|
|
47
|
+
setTimeout(function () {
|
|
48
|
+
delay += options.backoff;
|
|
49
|
+
block.call(self, retry);
|
|
50
|
+
}, delay);
|
|
51
|
+
} else {
|
|
52
|
+
callback.fail(err || new Error('Eventually block timed out'));
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
block.call(this, retry);
|
|
57
|
+
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* A short-cut for calling a service operation and waiting for it to
|
|
62
|
+
* finish execution before moving onto the next step in the scenario.
|
|
63
|
+
*/
|
|
64
|
+
request: function request(svc, operation, params, next, extra) {
|
|
65
|
+
var world = this;
|
|
66
|
+
|
|
67
|
+
if (!svc) svc = this.service;
|
|
68
|
+
if (typeof svc == 'string') svc = this[svc];
|
|
69
|
+
|
|
70
|
+
svc[operation](params, function(err, data) {
|
|
71
|
+
world.response = this;
|
|
72
|
+
world.error = err;
|
|
73
|
+
world.data = data;
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
if (typeof next.condition === 'function') {
|
|
77
|
+
var condition = next.condition.call(world, world);
|
|
78
|
+
if (!condition) {
|
|
79
|
+
next.fail(new Error('Request success condition failed'));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (extra) {
|
|
85
|
+
extra.call(world, world.response);
|
|
86
|
+
next.call(world);
|
|
87
|
+
}
|
|
88
|
+
else if (extra !== false && err) {
|
|
89
|
+
world.unexpectedError(world.response, next);
|
|
90
|
+
} else {
|
|
91
|
+
next.call(world);
|
|
92
|
+
}
|
|
93
|
+
} catch (err) {
|
|
94
|
+
next.fail(err);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Given a response that contains an error, this fails the current
|
|
101
|
+
* step with a formatted error message that indicates which service and
|
|
102
|
+
* operation failed.
|
|
103
|
+
*/
|
|
104
|
+
unexpectedError: function unexpectedError(resp, next) {
|
|
105
|
+
var svc = resp.request.service.api.serviceName;
|
|
106
|
+
var op = resp.request.operation;
|
|
107
|
+
var code = resp.error.code;
|
|
108
|
+
var msg = resp.error.message;
|
|
109
|
+
var err = 'Received unexpected error from ' + svc + '.' + op + ', ' + code + ': ' + msg;
|
|
110
|
+
next.fail(new Error(err));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
var realExit = process.exit;
|
|
2
|
+
|
|
3
|
+
module.exports = function () {
|
|
4
|
+
var world = require("./world.js").WorldInstance;
|
|
5
|
+
this.World = require("./world.js").World;
|
|
6
|
+
|
|
7
|
+
world.cleanupTasks = new world.AWS.SequentialExecutor();
|
|
8
|
+
|
|
9
|
+
process.exit = function(code) {
|
|
10
|
+
var finalCallback = function() { realExit(code); };
|
|
11
|
+
world.cleanupTasks.emit('cleanup', [], finalCallback);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
this.AfterAll = function(callback) {
|
|
15
|
+
world.cleanupTasks.onAsync('cleanup', callback.bind(world));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
this.Before(function(callback) {
|
|
19
|
+
this.params = {};
|
|
20
|
+
callback();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
/* Global error code steps */
|
|
24
|
+
|
|
25
|
+
this.Then(/^the error code should be "([^"]*)"$/, function(code, callback) {
|
|
26
|
+
this.assert.ok(this.error, 'Response does not contain an error');
|
|
27
|
+
this.assert.equal(this.error.code, code);
|
|
28
|
+
callback();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
this.Then(/^the error message should (be|equal|match|contain):$/, function(matcher, message, callback) {
|
|
32
|
+
if (matcher === 'be') matcher = 'equal';
|
|
33
|
+
if (matcher === 'contain') matcher = 'match';
|
|
34
|
+
this.assert.ok(this.error, 'Response does not contain an error');
|
|
35
|
+
this.assert[matcher](this.error.message, message);
|
|
36
|
+
callback();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
this.Then(/^the status code should be (\d+)$/, function(status, callback) {
|
|
40
|
+
this.assert.equal(this.response.httpResponse.statusCode, parseInt(status));
|
|
41
|
+
callback();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
this.Then(/^I should get the error:$/, function(table, callback) {
|
|
45
|
+
var err = table.hashes()[0]
|
|
46
|
+
this.assert.equal(this.error.code, err.code);
|
|
47
|
+
this.assert.equal(this.error.message, err.message);
|
|
48
|
+
callback();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
this.Given(/^I have a "([^"]*)" service in the "([^"]*)" region$/, function(svc, region, callback) {
|
|
52
|
+
this.service = new this.AWS[svc]({ region: region });
|
|
53
|
+
callback();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
this.Given(/^I paginate the "([^"]*)" operation with limit (\d+)(?: and max pages (\d+))?$/, function(operation, limit, maxPages, callback) {
|
|
57
|
+
limit = parseInt(limit);
|
|
58
|
+
if (maxPages) maxPages = parseInt(maxPages);
|
|
59
|
+
|
|
60
|
+
var world = this;
|
|
61
|
+
this.numPages = 0;
|
|
62
|
+
this.numMarkers = 0
|
|
63
|
+
this.operation = operation;
|
|
64
|
+
this.paginationConfig = this.service.paginationConfig(operation);
|
|
65
|
+
this.params = this.params || {};
|
|
66
|
+
|
|
67
|
+
var marker = this.paginationConfig.outputToken;
|
|
68
|
+
if (this.paginationConfig.limitKey) {
|
|
69
|
+
this.params[this.paginationConfig.limitKey] = limit;
|
|
70
|
+
}
|
|
71
|
+
this.service[operation](this.params).eachPage(function (err, data) {
|
|
72
|
+
if (err) callback.fail(err);
|
|
73
|
+
else if (data === null) callback();
|
|
74
|
+
else if (maxPages && world.numPages === maxPages) {
|
|
75
|
+
callback();
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
if (data[marker]) world.numMarkers++;
|
|
80
|
+
world.numPages++;
|
|
81
|
+
world.data = data;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
this.Then(/^I should get more than one page$/, function(callback) {
|
|
87
|
+
this.assert.compare(this.numPages, '>', 1);
|
|
88
|
+
callback();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
this.Then(/^I should get (\d+) pages$/, function(numPages, callback) {
|
|
92
|
+
this.assert.equal(this.numPages, parseInt(numPages));
|
|
93
|
+
callback();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
this.Then(/^I should get numPages - 1 markers$/, function(callback) {
|
|
97
|
+
this.assert.equal(this.numMarkers, this.numPages - 1);
|
|
98
|
+
callback();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
this.Then(/^the last page should not contain a marker$/, function(callback) {
|
|
102
|
+
var marker = this.paginationConfig.outputToken;
|
|
103
|
+
this.assert.equal(this.data[marker], null);
|
|
104
|
+
callback();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
var world = require('./helpers');
|
|
2
|
+
world.AWS = require('../../lib/aws');
|
|
3
|
+
try {
|
|
4
|
+
world.AWS.config.loadFromPath(__dirname + '/../../configuration');
|
|
5
|
+
} catch (e) { }
|
|
6
|
+
|
|
7
|
+
var WorldConstructor = function WorldConstructor(callback) {
|
|
8
|
+
callback(world);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
exports.World = WorldConstructor;
|
|
12
|
+
exports.WorldInstance = world;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# language: en
|
|
2
|
+
@glacier
|
|
3
|
+
Feature: Amazon Glacier
|
|
4
|
+
|
|
5
|
+
I want to use Amazon Glacier
|
|
6
|
+
|
|
7
|
+
@vault
|
|
8
|
+
Scenario: Creating a vault
|
|
9
|
+
Given I have a Glacier vault
|
|
10
|
+
When I describe the Glacier vault
|
|
11
|
+
Then the result should contain a property NumberOfArchives with a number
|
|
12
|
+
|
|
13
|
+
@archive
|
|
14
|
+
Scenario: Uploading an archive
|
|
15
|
+
Given I have a Glacier vault
|
|
16
|
+
When I upload a 0.25MB Glacier archive to the vault
|
|
17
|
+
Then the result should contain the Glacier archive ID
|
|
18
|
+
And the result should contain the same tree hash checksum
|
|
19
|
+
And I delete the Glacier archive
|
|
20
|
+
|
|
21
|
+
@multipart
|
|
22
|
+
Scenario: Multi-part upload
|
|
23
|
+
Given I have a Glacier vault
|
|
24
|
+
When I initiate a Glacier multi-part upload on a 2.5MB archive in 1MB chunks
|
|
25
|
+
Then the result should contain the Glacier multi-part upload ID
|
|
26
|
+
And I send the Glacier archive data in chunks
|
|
27
|
+
And I complete the Glacier multi-part upload
|
|
28
|
+
Then the result should contain the Glacier archive ID
|
|
29
|
+
And the result should contain the same tree hash checksum
|
|
30
|
+
And I delete the Glacier archive
|
|
31
|
+
|
|
32
|
+
@error
|
|
33
|
+
Scenario: Error handling
|
|
34
|
+
Given I have a Glacier vault
|
|
35
|
+
And I upload a 0.05MB Glacier archive to the vault with incorrect checksum
|
|
36
|
+
Then the error code should be "InvalidParameterValueException"
|
|
37
|
+
And the error message should match:
|
|
38
|
+
"""
|
|
39
|
+
Checksum mismatch:
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
When I upload a 0.05MB Glacier archive to the vault with invalid checksum
|
|
43
|
+
Then the error code should be "InvalidParameterValueException"
|
|
44
|
+
And the error message should equal:
|
|
45
|
+
"""
|
|
46
|
+
Invalid x-amz-sha256-tree-hash: 000
|
|
47
|
+
"""
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
module.exports = function() {
|
|
2
|
+
this.Before("@glacier", function (callback) {
|
|
3
|
+
this.service = new this.AWS.Glacier();
|
|
4
|
+
callback();
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
this.Given(/^I have a Glacier vault$/, function(callback) {
|
|
8
|
+
this.vaultName = 'aws-sdk-js-integration';
|
|
9
|
+
var params = {vaultName: this.vaultName};
|
|
10
|
+
this.request(null, 'createVault', params, callback, false);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
this.Given(/^I upload a (\d+(?:\.\d+)?)MB Glacier archive to the vault( with (?:invalid|incorrect) checksum)?$/, function(size, invalid, callback) {
|
|
14
|
+
var data = new Buffer(parseFloat(size) * 1024 * 1024);
|
|
15
|
+
data.fill('0');
|
|
16
|
+
var params = {vaultName: this.vaultName, body: data};
|
|
17
|
+
if (invalid) {
|
|
18
|
+
if (invalid.match("invalid")) params.checksum = '000';
|
|
19
|
+
else params.checksum = '00000000000000000000000000000000';
|
|
20
|
+
}
|
|
21
|
+
this.request(null, 'uploadArchive', params, callback, false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
this.Then(/^the result should contain the Glacier archive ID$/, function(callback) {
|
|
25
|
+
this.archiveId = this.data.archiveId;
|
|
26
|
+
callback();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
this.Then(/^the result should contain the same tree hash checksum$/, function(callback) {
|
|
30
|
+
var hash = this.response.request.httpRequest.headers['x-amz-sha256-tree-hash'];
|
|
31
|
+
this.assert.equal(this.data.checksum, hash);
|
|
32
|
+
callback();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
this.When(/^I describe the Glacier vault$/, function(callback) {
|
|
36
|
+
var params = {vaultName: this.vaultName};
|
|
37
|
+
this.request(null, 'describeVault', params, callback);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
this.Then(/^I delete the Glacier archive$/, function(callback) {
|
|
41
|
+
var params = {vaultName: this.vaultName, archiveId: this.archiveId};
|
|
42
|
+
this.request(null, 'deleteArchive', params, callback);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
this.Then(/^I delete the Glacier vault$/, function(callback) {
|
|
46
|
+
var params = {vaultName: this.vaultName};
|
|
47
|
+
this.eventually(callback, function(next) {
|
|
48
|
+
this.request(null, 'deleteVault', params, next);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
this.When(/^I initiate a Glacier multi-part upload on a (\d+(?:\.\d+)?)MB archive in (\d+)MB chunks$/, function(totalSize, partSize, callback) {
|
|
53
|
+
// setup multi-part upload
|
|
54
|
+
this.uploadData = new Buffer(totalSize * 1024 * 1024);
|
|
55
|
+
this.uploadData.fill('0');
|
|
56
|
+
this.checksums = this.service.computeChecksums(this.uploadData);
|
|
57
|
+
this.partCounter = 0;
|
|
58
|
+
this.partSize = partSize * 1024 * 1024;
|
|
59
|
+
|
|
60
|
+
var params = {vaultName: this.vaultName, partSize: this.partSize.toString()};
|
|
61
|
+
this.request(null, 'initiateMultipartUpload', params, callback);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
this.Then(/^the result should contain the Glacier multi-part upload ID$/, function(callback) {
|
|
65
|
+
this.uploadId = this.data.uploadId;
|
|
66
|
+
callback();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
this.Then(/^I send the next part$/, function(callback) {
|
|
70
|
+
var start = this.partCounter;
|
|
71
|
+
var end = Math.min(start + this.partSize, this.uploadData.length);
|
|
72
|
+
var buf = this.uploadData.slice(start, end);
|
|
73
|
+
var range = 'bytes ' + start + '-' + (end-1) + '/*';
|
|
74
|
+
var params = {
|
|
75
|
+
vaultName: this.vaultName,
|
|
76
|
+
uploadId: this.uploadId,
|
|
77
|
+
range: range,
|
|
78
|
+
body: buf
|
|
79
|
+
};
|
|
80
|
+
this.request(null, 'uploadMultipartPart', params, callback);
|
|
81
|
+
this.partCounter += this.partSize;
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
this.Then(/^I send the Glacier archive data in chunks$/, function(callback) {
|
|
85
|
+
var numPartsLeft = Math.ceil(this.uploadData.length / this.partSize);
|
|
86
|
+
for (var i = 0; i < this.uploadData.length; i += this.partSize) {
|
|
87
|
+
var end = Math.min(i + this.partSize, this.uploadData.length);
|
|
88
|
+
var buf = this.uploadData.slice(i, end);
|
|
89
|
+
var range = 'bytes ' + i + '-' + (end-1) + '/*';
|
|
90
|
+
var params = {
|
|
91
|
+
vaultName: this.vaultName,
|
|
92
|
+
uploadId: this.uploadId,
|
|
93
|
+
range: range,
|
|
94
|
+
body: buf
|
|
95
|
+
};
|
|
96
|
+
this.service.uploadMultipartPart(params, function() {
|
|
97
|
+
if (--numPartsLeft == 0) callback();
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
this.Then(/^I complete the Glacier multi-part upload$/, function(callback) {
|
|
103
|
+
var params = {
|
|
104
|
+
vaultName: this.vaultName,
|
|
105
|
+
uploadId: this.uploadId,
|
|
106
|
+
archiveSize: this.uploadData.length.toString(),
|
|
107
|
+
checksum: this.checksums.treeHash
|
|
108
|
+
}
|
|
109
|
+
this.request(null, 'completeMultipartUpload', params, callback);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# language: en
|
|
2
|
+
@iam
|
|
3
|
+
Feature: IAM
|
|
4
|
+
|
|
5
|
+
I want to use IAM
|
|
6
|
+
|
|
7
|
+
Scenario: Users
|
|
8
|
+
Given I have an IAM username "js-test"
|
|
9
|
+
And I create an IAM user with the username
|
|
10
|
+
And I list the IAM users
|
|
11
|
+
Then the list should contain the user
|
|
12
|
+
And I delete the IAM user
|
|
13
|
+
|
|
14
|
+
Scenario: Roles
|
|
15
|
+
Given I create an IAM role with name prefix "aws-sdk-js"
|
|
16
|
+
Then the IAM role should exist
|
|
17
|
+
And I delete the IAM role
|
|
18
|
+
|
|
19
|
+
Scenario: Error handling
|
|
20
|
+
Given I have an IAM username "js-test-dupe"
|
|
21
|
+
And I create an IAM user with the username
|
|
22
|
+
And I create an IAM user with the username
|
|
23
|
+
Then the error code should be "EntityAlreadyExists"
|
|
24
|
+
And I delete the IAM user
|