fake_aws 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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
+