fake_aws 0.0.2 → 0.0.3

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +2 -0
  4. data/README.md +24 -16
  5. data/fake_aws.gemspec +4 -1
  6. data/lib/fake_aws.rb +10 -2
  7. data/lib/fake_aws/error.rb +16 -0
  8. data/lib/fake_aws/s3/bucket_on_disk.rb +26 -0
  9. data/lib/fake_aws/s3/error_index.rb +37 -0
  10. data/lib/fake_aws/s3/object_on_disk.rb +50 -0
  11. data/lib/fake_aws/s3/operations/get_object.rb +30 -23
  12. data/lib/fake_aws/s3/operations/put_bucket.rb +38 -0
  13. data/lib/fake_aws/s3/operations/put_object.rb +22 -36
  14. data/lib/fake_aws/s3/rack_app.rb +19 -6
  15. data/lib/fake_aws/s3/request.rb +100 -0
  16. data/lib/fake_aws/s3/responses/common.rb +37 -0
  17. data/lib/fake_aws/s3/responses/empty.rb +25 -0
  18. data/lib/fake_aws/s3/responses/error.rb +50 -0
  19. data/lib/fake_aws/s3/responses/success.rb +31 -0
  20. data/lib/fake_aws/version.rb +1 -1
  21. data/spec/integration/s3/get_object_spec.rb +35 -12
  22. data/spec/integration/s3/put_bucket_spec.rb +40 -0
  23. data/spec/integration/s3/put_object_spec.rb +12 -4
  24. data/spec/integration/s3/request_styles_spec.rb +54 -0
  25. data/spec/spec_helper.rb +1 -16
  26. data/spec/support/common_header_examples.rb +16 -0
  27. data/spec/support/s3_integration_helpers.rb +18 -0
  28. data/spec/support/xml_parsing_helper.rb +7 -0
  29. data/spec/unit/s3/bucket_on_disk_spec.rb +39 -0
  30. data/spec/unit/s3/error_index_spec.rb +17 -0
  31. data/spec/unit/s3/object_on_disk_spec.rb +82 -0
  32. data/spec/unit/s3/request_spec.rb +92 -0
  33. data/spec/unit/s3/responses/empty_spec.rb +14 -0
  34. data/spec/unit/s3/responses/error_spec.rb +49 -0
  35. data/spec/unit/s3/responses/success_spec.rb +25 -0
  36. metadata +82 -26
  37. data/lib/fake_aws/s3/object_store.rb +0 -66
  38. data/lib/fake_aws/s3/xml_error_response.rb +0 -29
  39. data/spec/unit/s3/object_store_spec.rb +0 -75
  40. data/spec/unit/s3/xml_error_response_spec.rb +0 -9
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Request styles:" do
4
+ include S3IntegrationHelpers
5
+
6
+ let(:bucket) { "mah-bucket" }
7
+ let(:file_name) { "mah-file.txt"}
8
+ let(:file_contents) { "Hello, world!" }
9
+
10
+ before do
11
+ FileUtils.mkdir(File.join(s3_path, bucket))
12
+ File.write(File.join(s3_path, bucket, file_name), file_contents)
13
+ end
14
+
15
+ shared_examples "GET Object" do
16
+ it "returns a 200" do
17
+ response = get_example_file(file_name)
18
+ expect(response.status).to eq(200)
19
+ end
20
+
21
+ it "returns the contents of the file" do
22
+ response = get_example_file(file_name)
23
+ expect(response.body).to eq(file_contents)
24
+ end
25
+ end
26
+
27
+ context "path-style GET Object" do
28
+ def get_example_file(key)
29
+ connection.get("http://s3.amazonaws.com/#{bucket}/#{key}")
30
+ end
31
+
32
+ include_examples "GET Object"
33
+ end
34
+
35
+ context "virtual hosted-style GET Object" do
36
+ def get_example_file(key)
37
+ connection.get("http://#{bucket}.s3.amazonaws.com/#{key}")
38
+ end
39
+
40
+ include_examples "GET Object"
41
+ end
42
+
43
+ context "CNAME-style GET Object" do
44
+ let(:bucket) { "mah-bucket.mah-domain.com" }
45
+
46
+ def get_example_file(key)
47
+ connection.get("http://#{bucket}/#{key}")
48
+ end
49
+
50
+ include_examples "GET Object"
51
+ end
52
+
53
+ end
54
+
data/spec/spec_helper.rb CHANGED
@@ -1,20 +1,5 @@
1
1
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
2
  require 'fake_aws'
3
- require 'faraday'
4
3
 
5
- module S3IntegrationSpecHelpers
6
- def self.included(base)
7
- base.let(:s3_path) { "tmp" }
4
+ Dir["./spec/support/**/*.rb"].sort.each {|f| require f}
8
5
 
9
- base.let(:connection) do
10
- Faraday.new do |connection|
11
- connection.adapter :rack, FakeAWS::S3::RackApp.new(s3_path)
12
- end
13
- end
14
-
15
- base.before do
16
- FileUtils.rm_r(s3_path) rescue Errno::ENOENT
17
- FileUtils.mkdir(s3_path)
18
- end
19
- end
20
- end
@@ -0,0 +1,16 @@
1
+ # Headers that should exist in every S3 response.
2
+ shared_examples "common response headers" do
3
+ it "has a Date header" do
4
+ time = Time.parse("2013-11-18 17:45")
5
+ allow(Time).to receive(:now).and_return(time)
6
+ expect(subject.headers["Date"]).to eq(time.httpdate)
7
+ end
8
+
9
+ it "has a Server header" do
10
+ expect(subject.headers["Server"]).to eq("AmazonS3")
11
+ end
12
+
13
+ it "has a request ID" do
14
+ expect(subject.headers["x-amz-request-id"]).to_not be_blank
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ require 'faraday'
2
+
3
+ module S3IntegrationHelpers
4
+ def self.included(base)
5
+ base.let(:s3_path) { "tmp" }
6
+
7
+ base.let(:connection) do
8
+ Faraday.new("http://s3.amazonaws.com") do |connection|
9
+ connection.adapter :rack, FakeAWS::S3::RackApp.new(s3_path)
10
+ end
11
+ end
12
+
13
+ base.before do
14
+ FileUtils.rm_r(s3_path) rescue Errno::ENOENT
15
+ FileUtils.mkdir(s3_path)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'nori'
2
+
3
+ module XMLParsingHelper
4
+ def parse_xml(xml)
5
+ Nori.new(:parser => :rexml).parse(xml)
6
+ end
7
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe FakeAWS::S3::BucketOnDisk do
4
+ let(:root_directory) { "tmp" }
5
+ let(:bucket) { "mah-bucket" }
6
+
7
+ subject { described_class.new(root_directory, bucket) }
8
+
9
+ let(:bucket_path) { "tmp/mah-bucket" }
10
+
11
+ before do
12
+ FileUtils.rm_r(root_directory) rescue Errno::ENOENT
13
+ end
14
+
15
+ describe "#exists?" do
16
+ it "returns true if the bucket directory exists" do
17
+ FileUtils.mkdir_p(bucket_path)
18
+ expect(subject.exists?).to be_truthy
19
+ end
20
+
21
+ it "returns false if the bucket directory doesn't exist" do
22
+ expect(subject.exists?).to be_falsy
23
+ end
24
+ end
25
+
26
+ describe "#create" do
27
+ it "creates the bucket directory" do
28
+ subject.create
29
+ expect(Dir.exists?(bucket_path)).to be_truthy
30
+ end
31
+ end
32
+
33
+ describe "#path" do
34
+ it "returns the path to the bucket" do
35
+ expect(subject.path).to eq(bucket_path)
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe FakeAWS::S3::ErrorIndex do
4
+
5
+ context ".error_for_code" do
6
+ it "returns something containing a description and status code for a known error" do
7
+ error = subject.error_for_code("NoSuchKey")
8
+ expect(error.description).to eq("The specified key does not exist.")
9
+ expect(error.status_code).to eq(404)
10
+ end
11
+
12
+ it "blows up if given an unknown error code" do
13
+ expect { subject.error_for_code("NotARealCode") }.to raise_error(FakeAWS::UnknownResponseErrorCode)
14
+ end
15
+ end
16
+
17
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe FakeAWS::S3::ObjectOnDisk do
4
+ let(:key) { "/mah-file.txt" }
5
+
6
+ let(:bucket_path) { "tmp/mah-bucket" }
7
+ let(:object_path) { "#{bucket_path}#{key}" }
8
+ let(:metadata_path) { "#{object_path}.metadata.json" }
9
+
10
+ let(:bucket_on_disk) { double(:path => bucket_path) }
11
+
12
+ subject { described_class.new(bucket_on_disk, key) }
13
+
14
+ before do
15
+ FileUtils.rm_r(bucket_path) rescue Errno::ENOENT
16
+ FileUtils.mkdir_p(bucket_path)
17
+ end
18
+
19
+ describe "#exists?" do
20
+ it "returns true if the object file exists" do
21
+ File.write(object_path, "Hello, world!")
22
+ expect(subject.exists?).to be_truthy
23
+ end
24
+
25
+ it "returns false if the object file doesn't exist" do
26
+ expect(subject.exists?).to be_falsy
27
+ end
28
+ end
29
+
30
+ describe "#write" do
31
+ it "writes the content to the object file" do
32
+ subject.write("Hello, world!", { "bunnies" => "scary" })
33
+
34
+ expect(File.read(object_path)).to eq("Hello, world!")
35
+ end
36
+
37
+ it "writes the metadata to the metadata file as JSON" do
38
+ subject.write("Hello, world!", { "bunnies" => "scary" })
39
+
40
+ expect(File.read(metadata_path)).to eq('{"bunnies":"scary"}')
41
+ end
42
+ end
43
+
44
+ describe "#read_content" do
45
+ it "reads the contents of the object file" do
46
+ File.write(object_path, "Hello, world!")
47
+
48
+ expect(subject.read_content.read).to eq("Hello, world!")
49
+ end
50
+ end
51
+
52
+ describe "#read_metadata" do
53
+ it "returns an empty hash if there's no metadata file" do
54
+ expect(subject.read_metadata).to eq({})
55
+ end
56
+
57
+ it "returns the JSON from the metadata file converted to a hash" do
58
+ File.write(metadata_path, '{"bunnies":"scary"}')
59
+
60
+ expect(subject.read_metadata).to eq("bunnies" => "scary")
61
+ end
62
+ end
63
+
64
+ describe "#object_path" do
65
+ it "returns the path to the object" do
66
+ expect(subject.object_path).to eq(object_path)
67
+ end
68
+ end
69
+
70
+ describe "#metadata_path" do
71
+ it "returns the path to the metadata" do
72
+ expect(subject.metadata_path).to eq(metadata_path)
73
+ end
74
+ end
75
+
76
+ describe "#directory_path" do
77
+ it "returns the path to the directory containing the object" do
78
+ expect(subject.directory_path).to eq(bucket_path)
79
+ end
80
+ end
81
+
82
+ end
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+
3
+ describe FakeAWS::S3::Request do
4
+ subject { described_class.new(env) }
5
+
6
+ context "#method" do
7
+ it "returns the request method" do
8
+ request = described_class.new("REQUEST_METHOD" => "GET")
9
+ expect(request.method).to eq("GET")
10
+ end
11
+ end
12
+
13
+ context "#content_type" do
14
+ it "returns the content type" do
15
+ request = described_class.new("CONTENT_TYPE" => "text/plain")
16
+ expect(request.content_type).to eq("text/plain")
17
+ end
18
+ end
19
+
20
+ context "#content" do
21
+ it "reads and returns the Rack input" do
22
+ rack_input = double("rack.input")
23
+ expect(rack_input).to receive(:read) { "foo" }
24
+ request = described_class.new("rack.input" => rack_input)
25
+ expect(request.content).to eq("foo")
26
+ end
27
+ end
28
+
29
+ context "#http_headers" do
30
+ it "returns the HTTP headers" do
31
+ request = described_class.new("HTTP_X_FOO" => "foo", "HTTP_X_BAR" => "bar")
32
+ expect(request.http_headers).to eq("x-foo" => "foo", "x-bar" => "bar")
33
+ end
34
+
35
+ it "ignores non-HTTP headers" do
36
+ request = described_class.new("FOO" => "foo")
37
+ expect(request.http_headers).to eq({})
38
+ end
39
+ end
40
+
41
+ shared_examples "request parsing" do
42
+ context "bucket request" do
43
+ let(:key) { "/" }
44
+
45
+ it "extracts the bucket" do
46
+ expect(request.bucket).to eq(bucket)
47
+ end
48
+
49
+ it "has no key" do
50
+ expect(request.has_key?).to be_falsy
51
+ end
52
+ end
53
+
54
+ context "object request" do
55
+ let(:key) { "/mah-object.txt" }
56
+
57
+ it "extracts the bucket" do
58
+ expect(request.bucket).to eq(bucket)
59
+ end
60
+
61
+ it "has a key" do
62
+ expect(request.has_key?).to be_truthy
63
+ end
64
+
65
+ it "extracts the key" do
66
+ expect(request.key).to eq(key)
67
+ end
68
+ end
69
+ end
70
+
71
+ context "path-style" do
72
+ let(:bucket) { "mah-bucket" }
73
+ subject(:request) { described_class.new("SERVER_NAME" => "s3.amazonaws.com", "PATH_INFO" => "/#{bucket}#{key}") }
74
+
75
+ include_examples "request parsing"
76
+ end
77
+
78
+ context "virtual hosted-style" do
79
+ let(:bucket) { "mah-bucket" }
80
+ subject(:request) { described_class.new("SERVER_NAME" => "#{bucket}.s3.amazonaws.com", "PATH_INFO" => key) }
81
+
82
+ include_examples "request parsing"
83
+ end
84
+
85
+ context "CNAME-style" do
86
+ let(:bucket) { "mah-bucket.mah-domain.com" }
87
+ subject(:request) { described_class.new("SERVER_NAME" => bucket, "PATH_INFO" => key) }
88
+
89
+ include_examples "request parsing"
90
+ end
91
+
92
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe FakeAWS::S3::Responses::Empty do
4
+ include_examples "common response headers"
5
+
6
+ it "has a status code of 200" do
7
+ expect(subject.status_code).to eq(200)
8
+ end
9
+
10
+ it "has an empty body" do
11
+ expect(subject.body).to be_empty
12
+ end
13
+
14
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe FakeAWS::S3::Responses::Error do
4
+
5
+ # Stub out looking up the error information:
6
+ let(:error_code) { "NoSuchKey" }
7
+ let(:error) { double(:description => "The specified key does not exist.", :status_code => 404) }
8
+ let(:error_index) { double(:error_for_code => error) }
9
+ before { stub_const("FakeAWS::S3::ErrorIndex", error_index) }
10
+
11
+ let(:resource) { "/mah-bucket/mah-object.txt" }
12
+
13
+ subject { described_class.new(error_code, "Resource" => resource) }
14
+
15
+ include_examples "common response headers"
16
+
17
+ it "has the right status code" do
18
+ expect(subject.status_code).to eq(error.status_code)
19
+ end
20
+
21
+ it "has a content type of XML" do
22
+ expect(subject.headers["Content-Type"]).to eq("application/xml")
23
+ end
24
+
25
+ context "body" do
26
+ include XMLParsingHelper
27
+
28
+ let(:parsed_body) { parse_xml(subject.body) }
29
+
30
+ it "contains the right code" do
31
+ expect(parsed_body["Error"]["Code"]).to eq(error_code)
32
+ end
33
+
34
+ it "contains the right message" do
35
+ expect(parsed_body["Error"]["Message"]).to eq(error.description)
36
+ end
37
+
38
+ it "contains any additional fields passed in" do
39
+ expect(parsed_body["Error"]["Resource"]).to eq(resource)
40
+ end
41
+
42
+ it "contains the right request ID" do
43
+ expect(parsed_body["Error"]["RequestId"]).to eq(subject.headers["x-amz-request-id"])
44
+ end
45
+ end
46
+
47
+ end
48
+
49
+
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe FakeAWS::S3::Responses::Success do
4
+
5
+ let(:headers) { { "Content-Type" => "text/plain" } }
6
+ let(:body) { "Hello, world!" }
7
+
8
+ subject { described_class.new(headers, body) }
9
+
10
+ include_examples "common response headers"
11
+
12
+ it "has a status code of 200" do
13
+ expect(subject.status_code).to eq(200)
14
+ end
15
+
16
+ it "has the right body" do
17
+ expect(subject.body).to eq(body)
18
+ end
19
+
20
+ it "has the right content type" do
21
+ expect(subject.headers["Content-Type"]).to eq("text/plain")
22
+ end
23
+
24
+ end
25
+