defra_ruby_aws 0.1.0
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.
- checksums.yaml +7 -0
- data/README.md +93 -0
- data/Rakefile +33 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/defra_ruby.rb +7 -0
- data/lib/defra_ruby/aws.rb +30 -0
- data/lib/defra_ruby/aws/bucket.rb +82 -0
- data/lib/defra_ruby/aws/configuration.rb +19 -0
- data/lib/defra_ruby/aws/response.rb +31 -0
- data/lib/defra_ruby/aws/services/bucket_loader_service.rb +32 -0
- data/lib/defra_ruby/aws/services/concerns/has_aws_bucket_configuration.rb +22 -0
- data/lib/defra_ruby/aws/services/presigned_url_service.rb +32 -0
- data/lib/defra_ruby/aws/version.rb +7 -0
- data/spec/defra_ruby_aws_spec.rb +7 -0
- data/spec/examples.txt +17 -0
- data/spec/features/upload_file_to_bucket_spec.rb +51 -0
- data/spec/lib/defra_ruby/aws/bucket_spec.rb +89 -0
- data/spec/lib/defra_ruby/aws/configuration_spec.rb +23 -0
- data/spec/lib/defra_ruby/aws/response_spec.rb +47 -0
- data/spec/lib/defra_ruby/aws/services/bucket_loader_service_spec.rb +37 -0
- data/spec/lib/defra_ruby/aws/services/presigned_url_service_spec.rb +32 -0
- data/spec/spec_helper.rb +83 -0
- data/spec/support/aws_sdk_s3.rb +4 -0
- data/spec/support/dotenv.rb +4 -0
- data/spec/support/pry.rb +7 -0
- data/spec/support/simplecov.rb +13 -0
- data/spec/support/webmock.rb +4 -0
- metadata +212 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8f98773dfc3468b835ccb7120609f527544bb794
|
4
|
+
data.tar.gz: 450ba740fa675f36bcd7b1c072524e06306e0f0f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bce99a5fbe92846cdf796771c153b3a90d2fef9459458f87f89e6626b24011c3bff84f5a42ba8ef4e457fa9bc297e4c59e8774fffdb958d0573fc6a46f524fd3
|
7
|
+
data.tar.gz: 27d93f4cc90f7d8eb5445017a990215afec9e345d9121dd04243fd734854cfd8362c7c1403b7c8891199b26a236b0871c526b345075cd12c730957b28eba9f86
|
data/README.md
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
# DefraRuby::Aws
|
2
|
+
|
3
|
+
[](https://travis-ci.com/DEFRA/defra-ruby-aws)
|
4
|
+
[](https://codeclimate.com/github/DEFRA/defra-ruby-aws/maintainability)
|
5
|
+
[](https://codeclimate.com/github/DEFRA/defra-ruby-aws/test_coverage)
|
6
|
+
[](https://hakiri.io/github/DEFRA/defra-ruby-aws/master)
|
7
|
+
[](https://badge.fury.io/rb/defra_ruby_aws)
|
8
|
+
[](http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3)
|
9
|
+
|
10
|
+
Package of Ruby helpers for connecting Rails applications to AWS S3.
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem 'defra_ruby_aws'
|
18
|
+
```
|
19
|
+
|
20
|
+
And then update your dependencies by calling
|
21
|
+
|
22
|
+
```bash
|
23
|
+
bundle install
|
24
|
+
```
|
25
|
+
|
26
|
+
## Configuration
|
27
|
+
|
28
|
+
Add a new bucket with:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
# config/initializers/defra_ruby_aws.rb
|
32
|
+
require "defra_ruby/aws"
|
33
|
+
|
34
|
+
DefraRuby::Aws.configure do |config|
|
35
|
+
config.buckets = [{
|
36
|
+
# bucket's name, required
|
37
|
+
name: "defra-ruby-aws",
|
38
|
+
# AWS bucket access credentials, required
|
39
|
+
credentials: {
|
40
|
+
access_key_id: "ACCESS_KEY_ID",
|
41
|
+
secret_access_key: "SECRET_ACCESS_KEY"
|
42
|
+
},
|
43
|
+
# optional - Default to "eu-west-1"
|
44
|
+
region: "eu-west-1"
|
45
|
+
}]
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
## Usage
|
50
|
+
|
51
|
+
### Upload a file
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
file_to_upload = Tempfile.new("test-upload-file.csv")
|
55
|
+
bucket = DefraRuby::Aws.get_bucket("defra-ruby-aws")
|
56
|
+
response = bucket.load(file_to_upload)
|
57
|
+
|
58
|
+
if response.successful?
|
59
|
+
# Do something
|
60
|
+
else
|
61
|
+
response.error # return the failure error
|
62
|
+
# Do something else
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
### Generate a presigned URL for download
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
bucket = DefraRuby::Aws.get_bucket("defra-ruby-aws")
|
70
|
+
presigned_url = bucket.presigned_url("test-upload-file.csv")
|
71
|
+
```
|
72
|
+
|
73
|
+
## Contributing to this project
|
74
|
+
|
75
|
+
If you have an idea you'd like to contribute please log an issue.
|
76
|
+
|
77
|
+
All contributions should be submitted via a pull request.
|
78
|
+
|
79
|
+
## License
|
80
|
+
|
81
|
+
THIS INFORMATION IS LICENSED UNDER THE CONDITIONS OF THE OPEN GOVERNMENT LICENCE found at:
|
82
|
+
|
83
|
+
http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3
|
84
|
+
|
85
|
+
The following attribution statement MUST be cited in your products and applications when using this information.
|
86
|
+
|
87
|
+
> Contains public sector information licensed under the Open Government license v3
|
88
|
+
|
89
|
+
### About the license
|
90
|
+
|
91
|
+
The Open Government Licence (OGL) was developed by the Controller of Her Majesty's Stationery Office (HMSO) to enable information providers in the public sector to license the use and re-use of their information under a common open licence.
|
92
|
+
|
93
|
+
It is designed to encourage use and re-use of information freely and flexibly, with only a few conditions.
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
begin
|
4
|
+
require "bundler/setup"
|
5
|
+
rescue LoadError
|
6
|
+
puts "You must `gem install bundler` and `bundle install` to run rake tasks"
|
7
|
+
end
|
8
|
+
|
9
|
+
Bundler::GemHelper.install_tasks
|
10
|
+
|
11
|
+
# This is wrapped to prevent an error when rake is called in environments where
|
12
|
+
# rspec may not be available, e.g. production. As such we don't need to handle
|
13
|
+
# the error.
|
14
|
+
# rubocop:disable Lint/HandleExceptions
|
15
|
+
begin
|
16
|
+
require "rspec/core/rake_task"
|
17
|
+
|
18
|
+
RSpec::Core::RakeTask.new(:spec)
|
19
|
+
|
20
|
+
task default: :spec
|
21
|
+
rescue LoadError
|
22
|
+
# no rspec available
|
23
|
+
end
|
24
|
+
|
25
|
+
begin
|
26
|
+
require "github_changelog_generator/task"
|
27
|
+
|
28
|
+
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
29
|
+
end
|
30
|
+
rescue LoadError
|
31
|
+
# no changelog available
|
32
|
+
end
|
33
|
+
# rubocop:enable Lint/HandleExceptions
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "defra_ruby/aws"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/defra_ruby.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "aws/bucket"
|
4
|
+
require_relative "aws/response"
|
5
|
+
require_relative "aws/configuration"
|
6
|
+
|
7
|
+
require_relative "aws/services/concerns/has_aws_bucket_configuration"
|
8
|
+
require_relative "aws/services/bucket_loader_service"
|
9
|
+
require_relative "aws/services/presigned_url_service"
|
10
|
+
|
11
|
+
module DefraRuby
|
12
|
+
module Aws
|
13
|
+
class << self
|
14
|
+
attr_accessor :configuration
|
15
|
+
|
16
|
+
def configure
|
17
|
+
require "aws-sdk-s3"
|
18
|
+
|
19
|
+
self.configuration ||= Configuration.new
|
20
|
+
yield(configuration)
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_bucket(bucket_name)
|
24
|
+
configuration.buckets.select do |bucket|
|
25
|
+
bucket.bucket_name == bucket_name
|
26
|
+
end.first
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DefraRuby
|
4
|
+
module Aws
|
5
|
+
class Bucket
|
6
|
+
attr_reader :bucket_name, :credentials, :region
|
7
|
+
|
8
|
+
def initialize(configs)
|
9
|
+
@credentials = configs[:credentials]
|
10
|
+
@bucket_name = configs[:name]
|
11
|
+
@region = setup_region(configs[:region])
|
12
|
+
|
13
|
+
validate!
|
14
|
+
end
|
15
|
+
|
16
|
+
def access_key_id
|
17
|
+
credentials[:access_key_id]
|
18
|
+
end
|
19
|
+
|
20
|
+
def secret_access_key
|
21
|
+
credentials[:secret_access_key]
|
22
|
+
end
|
23
|
+
|
24
|
+
def load(file)
|
25
|
+
BucketLoaderService.run(self, file)
|
26
|
+
end
|
27
|
+
|
28
|
+
def presigned_url(file_name)
|
29
|
+
PresignedUrlService.run(self, file_name)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_writer :region
|
35
|
+
|
36
|
+
def setup_region(region)
|
37
|
+
return default_region if region.nil? || region.empty?
|
38
|
+
|
39
|
+
region
|
40
|
+
end
|
41
|
+
|
42
|
+
def default_region
|
43
|
+
"eu-west-1"
|
44
|
+
end
|
45
|
+
|
46
|
+
def validate!
|
47
|
+
validate_presence_of_name!
|
48
|
+
validate_presence_of_credentials!
|
49
|
+
end
|
50
|
+
|
51
|
+
def validate_presence_of_name!
|
52
|
+
raise_not_valid_name if bucket_name.nil? || bucket_name.empty?
|
53
|
+
end
|
54
|
+
|
55
|
+
def validate_presence_of_credentials!
|
56
|
+
raise_missing_credentials if empty?(credentials)
|
57
|
+
raise_missing_access_key if empty?(access_key_id)
|
58
|
+
raise_missing_secret_access_key if empty?(secret_access_key)
|
59
|
+
end
|
60
|
+
|
61
|
+
def raise_not_valid_name
|
62
|
+
raise("DefraRuby::Aws buckets configurations: missing bucket name")
|
63
|
+
end
|
64
|
+
|
65
|
+
def raise_missing_credentials
|
66
|
+
raise("DefraRuby::Aws buckets configurations: missing credentials for bucket #{bucket_name}")
|
67
|
+
end
|
68
|
+
|
69
|
+
def raise_missing_access_key
|
70
|
+
raise("DefraRuby::Aws buckets configurations: missing access key id for bucket #{bucket_name}")
|
71
|
+
end
|
72
|
+
|
73
|
+
def raise_missing_secret_access_key
|
74
|
+
raise("DefraRuby::Aws buckets configurations: missing secret access key for bucket #{bucket_name}")
|
75
|
+
end
|
76
|
+
|
77
|
+
def empty?(object)
|
78
|
+
object.nil? || object.empty?
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DefraRuby
|
4
|
+
module Aws
|
5
|
+
class Configuration
|
6
|
+
attr_reader :buckets
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@buckets = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def buckets=(buckets_configurations)
|
13
|
+
@buckets = buckets_configurations.map do |configs|
|
14
|
+
Bucket.new(configs)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DefraRuby
|
4
|
+
module Aws
|
5
|
+
class Response
|
6
|
+
attr_reader :error
|
7
|
+
|
8
|
+
def initialize(response_exe)
|
9
|
+
@success = true
|
10
|
+
@error = nil
|
11
|
+
|
12
|
+
capture_response(response_exe)
|
13
|
+
end
|
14
|
+
|
15
|
+
def successful?
|
16
|
+
success
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :success
|
22
|
+
|
23
|
+
def capture_response(response_exe)
|
24
|
+
response_exe.call
|
25
|
+
rescue StandardError => e
|
26
|
+
@error = e
|
27
|
+
@success = false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DefraRuby
|
4
|
+
module Aws
|
5
|
+
class BucketLoaderService
|
6
|
+
include HasAwsBucketConfiguration
|
7
|
+
|
8
|
+
def self.run(bucket, file)
|
9
|
+
new(bucket, file).run
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(bucket, file)
|
13
|
+
@bucket = bucket
|
14
|
+
@file = file
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
Response.new(response_exe)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :bucket, :file
|
24
|
+
|
25
|
+
def response_exe
|
26
|
+
lambda do
|
27
|
+
s3_bucket.object(File.basename(file.path)).upload_file(file.path, server_side_encryption: :AES256)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DefraRuby
|
4
|
+
module Aws
|
5
|
+
module HasAwsBucketConfiguration
|
6
|
+
def s3_bucket
|
7
|
+
s3.bucket(bucket.bucket_name)
|
8
|
+
end
|
9
|
+
|
10
|
+
def s3
|
11
|
+
::Aws::S3::Resource.new(
|
12
|
+
region: bucket.region,
|
13
|
+
credentials: aws_credentials
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
def aws_credentials
|
18
|
+
::Aws::Credentials.new(bucket.access_key_id, bucket.secret_access_key)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DefraRuby
|
4
|
+
module Aws
|
5
|
+
class PresignedUrlService
|
6
|
+
include HasAwsBucketConfiguration
|
7
|
+
|
8
|
+
def self.run(bucket, file_name)
|
9
|
+
new(bucket, file_name).run
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(bucket, file_name)
|
13
|
+
@bucket = bucket
|
14
|
+
@file_name = file_name
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
s3_bucket.object(file_name).presigned_url(
|
19
|
+
:get,
|
20
|
+
expires_in: 20 * 60, # 20 minutes in seconds
|
21
|
+
secure: true,
|
22
|
+
response_content_type: "text/csv",
|
23
|
+
response_content_disposition: "attachment; filename=#{file_name}"
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_reader :bucket, :file_name
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/spec/examples.txt
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
example_id | status | run_time |
|
2
|
+
----------------------------------------------------------------------- | ------ | --------------- |
|
3
|
+
./spec/defra_ruby_aws_spec.rb[1:1] | passed | 0.00122 seconds |
|
4
|
+
./spec/features/upload_file_to_bucket_spec.rb[1:1] | passed | 0.0124 seconds |
|
5
|
+
./spec/features/upload_file_to_bucket_spec.rb[1:2] | passed | 0.00574 seconds |
|
6
|
+
./spec/lib/defra_ruby/aws/bucket_spec.rb[1:1:1:1] | passed | 0.00174 seconds |
|
7
|
+
./spec/lib/defra_ruby/aws/bucket_spec.rb[1:1:2:1] | passed | 0.0001 seconds |
|
8
|
+
./spec/lib/defra_ruby/aws/bucket_spec.rb[1:1:3:1] | passed | 0.00017 seconds |
|
9
|
+
./spec/lib/defra_ruby/aws/bucket_spec.rb[1:1:4:1] | passed | 0.00014 seconds |
|
10
|
+
./spec/lib/defra_ruby/aws/bucket_spec.rb[1:2:1] | passed | 0.00213 seconds |
|
11
|
+
./spec/lib/defra_ruby/aws/configuration_spec.rb[1:1:1] | passed | 0.00061 seconds |
|
12
|
+
./spec/lib/defra_ruby/aws/response_spec.rb[1:1:1:1] | passed | 0.00011 seconds |
|
13
|
+
./spec/lib/defra_ruby/aws/response_spec.rb[1:1:2:1] | passed | 0.00014 seconds |
|
14
|
+
./spec/lib/defra_ruby/aws/response_spec.rb[1:2:1:1] | passed | 0.0001 seconds |
|
15
|
+
./spec/lib/defra_ruby/aws/response_spec.rb[1:2:2:1] | passed | 0.00011 seconds |
|
16
|
+
./spec/lib/defra_ruby/aws/services/bucket_loader_service_spec.rb[1:1:1] | passed | 0.01269 seconds |
|
17
|
+
./spec/lib/defra_ruby/aws/services/presigned_url_service_spec.rb[1:1:1] | passed | 0.00368 seconds |
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe "Defra Ruby AWS" do
|
6
|
+
it "Upload a file to an AWS bucket" do
|
7
|
+
configure_gem
|
8
|
+
stub_successful_request
|
9
|
+
|
10
|
+
bucket = DefraRuby::Aws.get_bucket("bulk-test")
|
11
|
+
response = bucket.load(Tempfile.new("test-bucket-load.test"))
|
12
|
+
|
13
|
+
expect(response).to be_successful
|
14
|
+
end
|
15
|
+
|
16
|
+
it "fails gracefully" do
|
17
|
+
configure_gem
|
18
|
+
stub_failing_request
|
19
|
+
|
20
|
+
bucket = DefraRuby::Aws.get_bucket("bulk-test")
|
21
|
+
response = bucket.load(Tempfile.new("test-bucket-load.test"))
|
22
|
+
|
23
|
+
expect(response).to_not be_successful
|
24
|
+
expect(response.error).to be_a(Aws::S3::Errors::Forbidden)
|
25
|
+
end
|
26
|
+
|
27
|
+
def configure_gem
|
28
|
+
DefraRuby::Aws.configure do |config|
|
29
|
+
config.buckets = [{
|
30
|
+
name: "bulk-test",
|
31
|
+
credentials: {
|
32
|
+
access_key_id: "ACCESS_KEY_ID",
|
33
|
+
secret_access_key: "SECRET_ACCESS_KEY"
|
34
|
+
}
|
35
|
+
}]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def stub_successful_request
|
40
|
+
stub_request(:put, %r{https:\/\/bulk-test\.s3\.eu-west-1\.amazonaws\.com\/test-bucket-load\..+})
|
41
|
+
end
|
42
|
+
|
43
|
+
def stub_failing_request
|
44
|
+
stub_request(
|
45
|
+
:put,
|
46
|
+
%r{https:\/\/bulk-test\.s3\.eu-west-1\.amazonaws\.com\/test-bucket-load\..+}
|
47
|
+
).to_return(
|
48
|
+
status: 403
|
49
|
+
)
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
module DefraRuby
|
6
|
+
module Aws
|
7
|
+
RSpec.describe Bucket do
|
8
|
+
subject(:bucket) { described_class.new(configs) }
|
9
|
+
|
10
|
+
describe "#initialize" do
|
11
|
+
context "when a name configuration is missing" do
|
12
|
+
let(:configs) do
|
13
|
+
{
|
14
|
+
name: nil,
|
15
|
+
credentials: {}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
it "raises an error" do
|
20
|
+
expect { bucket }.to raise_error("DefraRuby::Aws buckets configurations: missing bucket name")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when credentials configuration is missing" do
|
25
|
+
let(:configs) do
|
26
|
+
{
|
27
|
+
name: "foo",
|
28
|
+
credentials: {}
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
it "raises an error" do
|
33
|
+
expect { bucket }.to raise_error("DefraRuby::Aws buckets configurations: missing credentials for bucket foo")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when credentials access key id is missing" do
|
38
|
+
let(:configs) do
|
39
|
+
{
|
40
|
+
name: "foo",
|
41
|
+
credentials: {
|
42
|
+
secret_access_key: "secret"
|
43
|
+
}
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
it "raises an error" do
|
48
|
+
expect { bucket }.to raise_error("DefraRuby::Aws buckets configurations: missing access key id for bucket foo")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when credentials secret access key is missing" do
|
53
|
+
let(:configs) do
|
54
|
+
{
|
55
|
+
name: "foo",
|
56
|
+
credentials: {
|
57
|
+
access_key_id: "access_key"
|
58
|
+
}
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
it "raises an error" do
|
63
|
+
expect { bucket }.to raise_error("DefraRuby::Aws buckets configurations: missing secret access key for bucket foo")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#load" do
|
69
|
+
let(:configs) do
|
70
|
+
{
|
71
|
+
name: "foo",
|
72
|
+
credentials: {
|
73
|
+
secret_access_key: "secret",
|
74
|
+
access_key_id: "access_key"
|
75
|
+
}
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
it "loads the given file to the s3 bucket" do
|
80
|
+
result = double(:result)
|
81
|
+
file = double(:file)
|
82
|
+
|
83
|
+
expect(BucketLoaderService).to receive(:run).with(bucket, file).and_return(result)
|
84
|
+
expect(bucket.load(file)).to eq(result)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
module DefraRuby
|
6
|
+
module Aws
|
7
|
+
RSpec.describe Configuration do
|
8
|
+
subject(:configuration) { described_class.new }
|
9
|
+
|
10
|
+
describe "#buckets=" do
|
11
|
+
let(:buckets) { %i[foo bar baz] }
|
12
|
+
|
13
|
+
it "creates a list of buckets" do
|
14
|
+
expect(Bucket).to receive(:new).with(:foo)
|
15
|
+
expect(Bucket).to receive(:new).with(:bar)
|
16
|
+
expect(Bucket).to receive(:new).with(:baz)
|
17
|
+
|
18
|
+
configuration.buckets = buckets
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
module DefraRuby
|
6
|
+
module Aws
|
7
|
+
RSpec.describe Response do
|
8
|
+
subject(:response) { described_class.new(response_exe) }
|
9
|
+
|
10
|
+
describe "#successful?" do
|
11
|
+
context "when the response throws an error" do
|
12
|
+
let(:response_exe) { -> { raise "Boom!" } }
|
13
|
+
|
14
|
+
it "returns false" do
|
15
|
+
expect(response).to_not be_successful
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "when the response don't throw an error" do
|
20
|
+
let(:response_exe) { -> {} }
|
21
|
+
|
22
|
+
it "returns true" do
|
23
|
+
expect(response).to be_successful
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#error" do
|
29
|
+
context "when the response throws an error" do
|
30
|
+
let(:response_exe) { -> { raise StandardError, "Boom!" } }
|
31
|
+
|
32
|
+
it "returns the error" do
|
33
|
+
expect(response.error).to be_a(StandardError)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when the response don't throw an error" do
|
38
|
+
let(:response_exe) { -> {} }
|
39
|
+
|
40
|
+
it "returns a nil object" do
|
41
|
+
expect(response.error).to be_nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
module DefraRuby
|
6
|
+
module Aws
|
7
|
+
RSpec.describe BucketLoaderService do
|
8
|
+
describe "#run" do
|
9
|
+
let(:configs) do
|
10
|
+
{
|
11
|
+
credentials: {
|
12
|
+
access_key_id: "key_id",
|
13
|
+
secret_access_key: "secret"
|
14
|
+
},
|
15
|
+
name: "bulk"
|
16
|
+
}
|
17
|
+
end
|
18
|
+
let(:bucket) { Bucket.new(configs) }
|
19
|
+
|
20
|
+
it "loads the given file to the s3 bucket" do
|
21
|
+
aws_resource = double(:aws_resource)
|
22
|
+
s3_bucket = double(:s3_bulk_bucket)
|
23
|
+
file = double(:file, path: "foo/bar/baz/test.csv")
|
24
|
+
s3_object = double(:s3_object)
|
25
|
+
result = double(:result)
|
26
|
+
|
27
|
+
expect(::Aws::S3::Resource).to receive(:new).and_return(aws_resource)
|
28
|
+
expect(aws_resource).to receive(:bucket).with("bulk").and_return(s3_bucket)
|
29
|
+
expect(s3_bucket).to receive(:object).with("test.csv").and_return(s3_object)
|
30
|
+
expect(s3_object).to receive(:upload_file).with("foo/bar/baz/test.csv", server_side_encryption: :AES256).and_return(result)
|
31
|
+
|
32
|
+
expect(described_class.run(bucket, file)).to be_a(Response)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
module DefraRuby
|
6
|
+
module Aws
|
7
|
+
RSpec.describe PresignedUrlService do
|
8
|
+
describe ".run" do
|
9
|
+
let(:configs) do
|
10
|
+
{
|
11
|
+
name: "test",
|
12
|
+
credentials: {
|
13
|
+
access_key_id: "123",
|
14
|
+
secret_access_key: "Secret"
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
let(:bucket) { Bucket.new(configs) }
|
19
|
+
let(:presigned_url) { described_class.run(bucket, "testfile.csv") }
|
20
|
+
|
21
|
+
it "returns a presigned url for a given file in the bucket" do
|
22
|
+
expect(presigned_url).to include("https://test.s3.eu-west-1.amazonaws.com/testfile.csv")
|
23
|
+
expect(presigned_url).to include("response-content-disposition=attachment")
|
24
|
+
expect(presigned_url).to include("response-content-type=text%2Fcsv")
|
25
|
+
expect(presigned_url).to include("Amz-Expires")
|
26
|
+
expect(presigned_url).to include("Amz-Credential")
|
27
|
+
expect(presigned_url).to include("Amz-Signature")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
|
5
|
+
# Require and run our simplecov initializer as the very first thing we do.
|
6
|
+
# This is as per its docs https://github.com/colszowka/simplecov#getting-started
|
7
|
+
require "./spec/support/simplecov"
|
8
|
+
|
9
|
+
# Requires supporting ruby files with custom matchers and macros, etc, in
|
10
|
+
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
|
11
|
+
# run as spec files by default. This means that files in spec/support that end
|
12
|
+
# in _spec.rb will both be required and run as specs, causing the specs to be
|
13
|
+
# run twice. It is recommended that you do not name files matching this glob to
|
14
|
+
# end with _spec.rb. You can configure this pattern with the --pattern
|
15
|
+
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
|
16
|
+
#
|
17
|
+
# We make an exception for simplecov because that will already have been
|
18
|
+
# required and run at the very top of spec_helper.rb
|
19
|
+
support_files = Dir["./spec/support/**/*.rb"].reject { |file| file == "./spec/support/simplecov.rb" }
|
20
|
+
support_files.each { |f| require f }
|
21
|
+
|
22
|
+
RSpec.configure do |config|
|
23
|
+
# rspec-expectations config goes here. You can use an alternate
|
24
|
+
# assertion/expectation library such as wrong or the stdlib/minitest
|
25
|
+
# assertions if you prefer.
|
26
|
+
config.expect_with :rspec do |expectations|
|
27
|
+
# This option will default to `true` in RSpec 4. It makes the `description`
|
28
|
+
# and `failure_message` of custom matchers include text for helper methods
|
29
|
+
# defined using `chain`, e.g.:
|
30
|
+
# be_bigger_than(2).and_smaller_than(4).description
|
31
|
+
# # => "be bigger than 2 and smaller than 4"
|
32
|
+
# ...rather than:
|
33
|
+
# # => "be bigger than 2"
|
34
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
35
|
+
end
|
36
|
+
|
37
|
+
# rspec-mocks config goes here. You can use an alternate test double
|
38
|
+
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
39
|
+
config.mock_with :rspec do |mocks|
|
40
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
41
|
+
# a real object. This is generally recommended, and will default to
|
42
|
+
# `true` in RSpec 4.
|
43
|
+
mocks.verify_partial_doubles = true
|
44
|
+
end
|
45
|
+
|
46
|
+
# This option will default to `:apply_to_host_groups` in RSpec 4 (and will
|
47
|
+
# have no way to turn it off -- the option exists only for backwards
|
48
|
+
# compatibility in RSpec 3). It causes shared context metadata to be
|
49
|
+
# inherited by the metadata hash of host groups and examples, rather than
|
50
|
+
# triggering implicit auto-inclusion in groups with matching metadata.
|
51
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
52
|
+
|
53
|
+
# This allows you to limit a spec run to individual examples or groups
|
54
|
+
# you care about by tagging them with `:focus` metadata. When nothing
|
55
|
+
# is tagged with `:focus`, all examples get run. RSpec also provides
|
56
|
+
# aliases for `it`, `describe`, and `context` that include `:focus`
|
57
|
+
# metadata: `fit`, `fdescribe` and `fcontext`, respectively.
|
58
|
+
config.filter_run_when_matching :focus
|
59
|
+
|
60
|
+
# Allows RSpec to persist some state between runs in order to support
|
61
|
+
# the `--only-failures` and `--next-failure` CLI options. We recommend
|
62
|
+
# you configure your source control system to ignore this file.
|
63
|
+
config.example_status_persistence_file_path = "spec/examples.txt"
|
64
|
+
|
65
|
+
# Limits the available syntax to the non-monkey patched syntax that is
|
66
|
+
# recommended. For more details, see:
|
67
|
+
# - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
|
68
|
+
# - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
69
|
+
# - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
|
70
|
+
config.disable_monkey_patching!
|
71
|
+
|
72
|
+
# Run specs in random order to surface order dependencies. If you find an
|
73
|
+
# order dependency and want to debug it, you can fix the order by providing
|
74
|
+
# the seed, which is printed after each run.
|
75
|
+
# --seed 1234
|
76
|
+
config.order = :random
|
77
|
+
|
78
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
79
|
+
# Setting this allows you to use `--seed` to deterministically reproduce
|
80
|
+
# test failures related to randomization by passing the same `--seed` value
|
81
|
+
# as the one that triggered the failure.
|
82
|
+
Kernel.srand config.seed
|
83
|
+
end
|
data/spec/support/pry.rb
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Support debugging in the tests. Add `binding.pry` wherever you want execution
|
4
|
+
# to stop and the debugger to kick in.
|
5
|
+
# Details on the debugging commands can be found here
|
6
|
+
# https://github.com/deivid-rodriguez/pry-byebug#commands
|
7
|
+
require "pry-byebug"
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "simplecov"
|
4
|
+
|
5
|
+
# We start it with the rails param to ensure it includes coverage for all code
|
6
|
+
# started by the rails app, and not just the files touched by our unit tests.
|
7
|
+
# This gives us the most accurate assessment of our unit test coverage
|
8
|
+
# https://github.com/colszowka/simplecov#getting-started
|
9
|
+
SimpleCov.start do
|
10
|
+
# The version file is simply just that, so we do not feel the need to ensure
|
11
|
+
# we have a test for it
|
12
|
+
add_filter "lib/defra_ruby/aws/version"
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: defra_ruby_aws
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Defra
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-06-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: aws-sdk-s3
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: defra_ruby_style
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: dotenv
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: github_changelog_generator
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry-byebug
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: webmock
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
description: Package of AWS features commonly used in Defra Rails based digital services
|
140
|
+
email:
|
141
|
+
- alan.cruikshanks@environment-agency.gov.uk
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- README.md
|
147
|
+
- Rakefile
|
148
|
+
- bin/console
|
149
|
+
- bin/setup
|
150
|
+
- lib/defra_ruby.rb
|
151
|
+
- lib/defra_ruby/aws.rb
|
152
|
+
- lib/defra_ruby/aws/bucket.rb
|
153
|
+
- lib/defra_ruby/aws/configuration.rb
|
154
|
+
- lib/defra_ruby/aws/response.rb
|
155
|
+
- lib/defra_ruby/aws/services/bucket_loader_service.rb
|
156
|
+
- lib/defra_ruby/aws/services/concerns/has_aws_bucket_configuration.rb
|
157
|
+
- lib/defra_ruby/aws/services/presigned_url_service.rb
|
158
|
+
- lib/defra_ruby/aws/version.rb
|
159
|
+
- spec/defra_ruby_aws_spec.rb
|
160
|
+
- spec/examples.txt
|
161
|
+
- spec/features/upload_file_to_bucket_spec.rb
|
162
|
+
- spec/lib/defra_ruby/aws/bucket_spec.rb
|
163
|
+
- spec/lib/defra_ruby/aws/configuration_spec.rb
|
164
|
+
- spec/lib/defra_ruby/aws/response_spec.rb
|
165
|
+
- spec/lib/defra_ruby/aws/services/bucket_loader_service_spec.rb
|
166
|
+
- spec/lib/defra_ruby/aws/services/presigned_url_service_spec.rb
|
167
|
+
- spec/spec_helper.rb
|
168
|
+
- spec/support/aws_sdk_s3.rb
|
169
|
+
- spec/support/dotenv.rb
|
170
|
+
- spec/support/pry.rb
|
171
|
+
- spec/support/simplecov.rb
|
172
|
+
- spec/support/webmock.rb
|
173
|
+
homepage: https://github.com/DEFRA/defra-ruby-aws
|
174
|
+
licenses:
|
175
|
+
- The Open Government Licence (OGL) Version 3
|
176
|
+
metadata:
|
177
|
+
allowed_push_host: https://rubygems.org
|
178
|
+
post_install_message:
|
179
|
+
rdoc_options: []
|
180
|
+
require_paths:
|
181
|
+
- lib
|
182
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
183
|
+
requirements:
|
184
|
+
- - ">="
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '0'
|
187
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
188
|
+
requirements:
|
189
|
+
- - ">="
|
190
|
+
- !ruby/object:Gem::Version
|
191
|
+
version: '0'
|
192
|
+
requirements: []
|
193
|
+
rubyforge_project:
|
194
|
+
rubygems_version: 2.6.13
|
195
|
+
signing_key:
|
196
|
+
specification_version: 4
|
197
|
+
summary: Defra ruby on rails AWS helpers
|
198
|
+
test_files:
|
199
|
+
- spec/defra_ruby_aws_spec.rb
|
200
|
+
- spec/spec_helper.rb
|
201
|
+
- spec/examples.txt
|
202
|
+
- spec/features/upload_file_to_bucket_spec.rb
|
203
|
+
- spec/support/aws_sdk_s3.rb
|
204
|
+
- spec/support/simplecov.rb
|
205
|
+
- spec/support/webmock.rb
|
206
|
+
- spec/support/pry.rb
|
207
|
+
- spec/support/dotenv.rb
|
208
|
+
- spec/lib/defra_ruby/aws/configuration_spec.rb
|
209
|
+
- spec/lib/defra_ruby/aws/response_spec.rb
|
210
|
+
- spec/lib/defra_ruby/aws/bucket_spec.rb
|
211
|
+
- spec/lib/defra_ruby/aws/services/bucket_loader_service_spec.rb
|
212
|
+
- spec/lib/defra_ruby/aws/services/presigned_url_service_spec.rb
|