snapimage 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.autotest +3 -0
  2. data/.gitignore +19 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +22 -0
  6. data/README.md +29 -0
  7. data/Rakefile +2 -0
  8. data/bin/snapimage_generate_config +63 -0
  9. data/bin/snapimage_server +55 -0
  10. data/lib/snapimage.rb +24 -0
  11. data/lib/snapimage/config.rb +51 -0
  12. data/lib/snapimage/exceptions.rb +25 -0
  13. data/lib/snapimage/image/image.rb +96 -0
  14. data/lib/snapimage/image/image_name_utils.rb +131 -0
  15. data/lib/snapimage/middleware.rb +27 -0
  16. data/lib/snapimage/rack/request.rb +19 -0
  17. data/lib/snapimage/rack/request_file.rb +26 -0
  18. data/lib/snapimage/rack/response.rb +51 -0
  19. data/lib/snapimage/server.rb +50 -0
  20. data/lib/snapimage/server_actions/server_actions.authorize.rb +69 -0
  21. data/lib/snapimage/server_actions/server_actions.delete_resource_images.rb +23 -0
  22. data/lib/snapimage/server_actions/server_actions.generate_image.rb +167 -0
  23. data/lib/snapimage/server_actions/server_actions.list_resource_images.rb +23 -0
  24. data/lib/snapimage/server_actions/server_actions.sync_resource.rb +78 -0
  25. data/lib/snapimage/storage/storage.rb +120 -0
  26. data/lib/snapimage/storage/storage_server.local.rb +120 -0
  27. data/lib/snapimage/storage/storage_server.rb +110 -0
  28. data/lib/snapimage/version.rb +3 -0
  29. data/snapimage.gemspec +27 -0
  30. data/spec/acceptance/delete_resource_images_spec.rb +166 -0
  31. data/spec/acceptance/list_resource_images_spec.rb +158 -0
  32. data/spec/acceptance/modify_spec.rb +165 -0
  33. data/spec/acceptance/sync_spec.rb +260 -0
  34. data/spec/acceptance/upload_spec.rb +235 -0
  35. data/spec/snapimage/config_spec.rb +56 -0
  36. data/spec/snapimage/image/image_name_utils_spec.rb +127 -0
  37. data/spec/snapimage/image/image_spec.rb +71 -0
  38. data/spec/snapimage/middleware_spec.rb +27 -0
  39. data/spec/snapimage/rack/request_file_spec.rb +15 -0
  40. data/spec/snapimage/rack/request_spec.rb +52 -0
  41. data/spec/snapimage/rack/response_spec.rb +33 -0
  42. data/spec/snapimage/server_actions/server_actions.authorize_spec.rb +67 -0
  43. data/spec/snapimage/server_actions/server_actions.generate_image_spec.rb +146 -0
  44. data/spec/snapimage/server_actions/server_actions.sync_resource_spec.rb +91 -0
  45. data/spec/snapimage/server_spec.rb +55 -0
  46. data/spec/snapimage/storage/assets/local/resource_1/12345678-1x1-0x0x1x1-1x1-1.gif +0 -0
  47. data/spec/snapimage/storage/assets/local/resource_1/12345678-1x1-0x0x1x1-300x200-0.jpg +0 -0
  48. data/spec/snapimage/storage/assets/local/resource_1/12345678-1x1.png +0 -0
  49. data/spec/snapimage/storage/assets/local/resource_2/12345678-1x1-0x0x1x1-1x1-1.gif +0 -0
  50. data/spec/snapimage/storage/assets/local/resource_2/12345678-1x1-0x0x1x1-300x200-0.jpg +0 -0
  51. data/spec/snapimage/storage/assets/local/resource_2/12345678-1x1.png +0 -0
  52. data/spec/snapimage/storage/storage_server.local_spec.rb +150 -0
  53. data/spec/snapimage/storage/storage_server_spec.rb +97 -0
  54. data/spec/snapimage/storage/storage_spec.rb +49 -0
  55. data/spec/spec_helper.rb +18 -0
  56. data/spec/support/assets/config.json +8 -0
  57. data/spec/support/assets/config.yml +9 -0
  58. data/spec/support/assets/stub-1x1.png +0 -0
  59. data/spec/support/assets/stub-2048x100.png +0 -0
  60. data/spec/support/assets/stub-300x200.png +0 -0
  61. metadata +272 -0
@@ -0,0 +1,56 @@
1
+ require "spec_helper"
2
+
3
+ describe SnapImage::Config do
4
+ describe "#get_config" do
5
+ it "raises when the config is not a String or Hash" do
6
+ config = SnapImage::Config.new(1)
7
+ expect { config.get_config }.to raise_error SnapImage::UnknownConfigType
8
+ end
9
+
10
+ it "raises when the file is not YAML or JSON" do
11
+ config = SnapImage::Config.new("config.txt")
12
+ expect { config.get_config }.to raise_error SnapImage::UnknownFileType
13
+ end
14
+
15
+ it "raises when the file cannot be found" do
16
+ config = SnapImage::Config.new("config.yml")
17
+ expect { config.get_config }.to raise_error Errno::ENOENT
18
+ end
19
+
20
+ it "returns the config from a YAML file" do
21
+ config = SnapImage::Config.new(File.join(RSpec.root, "support/assets/config.yml"))
22
+ c = config.get_config
23
+ c["security_salt"].should eq "abc123"
24
+ c["storage_servers"].length.should eq 2
25
+ c["storage_servers"][0]["name"].should eq "storage 1"
26
+ c["storage_servers"][0]["type"].should eq "test"
27
+ c["storage_servers"][1]["name"].should eq "storage 2"
28
+ c["storage_servers"][1]["type"].should eq "test"
29
+ end
30
+
31
+ it "returns the config from a JSON file" do
32
+ config = SnapImage::Config.new(File.join(RSpec.root, "support/assets/config.json"))
33
+ c = config.get_config
34
+ c["security_salt"].should eq "abc123"
35
+ c["storage_servers"].length.should eq 2
36
+ c["storage_servers"][0]["name"].should eq "storage 1"
37
+ c["storage_servers"][0]["type"].should eq "test"
38
+ c["storage_servers"][1]["name"].should eq "storage 2"
39
+ c["storage_servers"][1]["type"].should eq "test"
40
+ end
41
+ end
42
+
43
+ describe "#[]" do
44
+ before do
45
+ @config = SnapImage::Config.new(File.join(RSpec.root, "support/assets/config.yml"))
46
+ end
47
+
48
+ it "returns the value when the key exists" do
49
+ @config["security_salt"].should eq "abc123"
50
+ end
51
+
52
+ it "returns nil when the key does not exist" do
53
+ @config["random"].should be_nil
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,127 @@
1
+ require "spec_helper"
2
+
3
+ describe SnapImage::ImageNameUtils do
4
+ before do
5
+ @image_path = File.join(RSpec.root, "support/assets/stub.png")
6
+ end
7
+
8
+ describe "#get_image_type" do
9
+ it "returns the correct type" do
10
+ SnapImage::ImageNameUtils.get_image_type("http://example.com/storage/abc/123/image.png").should eq "png"
11
+ end
12
+
13
+ it "returns jpg when the type is jpeg" do
14
+ SnapImage::ImageNameUtils.get_image_type("http://example.com/storage/abc/123/image.jpeg").should eq "jpg"
15
+ end
16
+ end
17
+
18
+ describe "#get_image_name_parts" do
19
+ it "raises an error when the image identifier is invalid" do
20
+ expect { SnapImage::ImageNameUtils.get_image_name_parts("a bad url") }.should raise_error SnapImage::InvalidImageIdentifier
21
+ end
22
+
23
+ it "returns all the parts given a base image url" do
24
+ url = "http://example.com/dkej2o3i-1024x768.png"
25
+ parts = SnapImage::ImageNameUtils.get_image_name_parts(url)
26
+ parts[:is_base].should be_true
27
+ parts[:full].should eq url
28
+ parts[:path].should eq "http://example.com"
29
+ parts[:filename].should eq "dkej2o3i-1024x768.png"
30
+ parts[:basename].should eq "dkej2o3i"
31
+ parts[:original_dimensions].should eq [1024, 768]
32
+ parts[:extname].should eq "png"
33
+ parts[:crop].should be_nil
34
+ parts[:dimensions].should be_nil
35
+ parts[:sharpen].should be_nil
36
+ end
37
+
38
+ it "returns all the parts given a modified image url" do
39
+ url = "http://example.com/dkej2o3i-1024x768-6x10x143x402-640x480-1.png"
40
+ parts = SnapImage::ImageNameUtils.get_image_name_parts(url)
41
+ parts[:is_base].should be_false
42
+ parts[:full].should eq url
43
+ parts[:path].should eq "http://example.com"
44
+ parts[:filename].should eq "dkej2o3i-1024x768-6x10x143x402-640x480-1.png"
45
+ parts[:basename].should eq "dkej2o3i"
46
+ parts[:original_dimensions].should eq [1024, 768]
47
+ parts[:crop][:x].should eq 6
48
+ parts[:crop][:y].should eq 10
49
+ parts[:crop][:width].should eq 143
50
+ parts[:crop][:height].should eq 402
51
+ parts[:dimensions].should eq [640, 480]
52
+ parts[:sharpen].should eq true
53
+ parts[:extname].should eq "png"
54
+ end
55
+
56
+ it "returns all the parts given a filename" do
57
+ url = "dkej2o3i-1024x768-6x10x143x402-640x480-1.png"
58
+ parts = SnapImage::ImageNameUtils.get_image_name_parts(url)
59
+ parts[:is_base].should be_false
60
+ parts[:full].should eq url
61
+ parts[:path].should eq ""
62
+ parts[:filename].should eq "dkej2o3i-1024x768-6x10x143x402-640x480-1.png"
63
+ parts[:basename].should eq "dkej2o3i"
64
+ parts[:original_dimensions].should eq [1024, 768]
65
+ parts[:crop][:x].should eq 6
66
+ parts[:crop][:y].should eq 10
67
+ parts[:crop][:width].should eq 143
68
+ parts[:crop][:height].should eq 402
69
+ parts[:dimensions].should eq [640, 480]
70
+ parts[:sharpen].should eq true
71
+ parts[:extname].should eq "png"
72
+ end
73
+ end
74
+
75
+ describe "#get_base_image_path" do
76
+ it "returns the base image name from the url" do
77
+ url = "http://example.com/dkej2o3i-1024x768-6x10x143x402-640x480-1.png"
78
+ SnapImage::ImageNameUtils.get_base_image_path(url).should eq "http://example.com/dkej2o3i-1024x768.png"
79
+ end
80
+ end
81
+
82
+ describe "#get_resized_image_name" do
83
+ it "returns the resized name given a base image" do
84
+ name = SnapImage::ImageNameUtils.get_resized_image_name("12345678-2048x100.png", 1024, 50)
85
+ name.should eq "12345678-1024x50.png"
86
+ end
87
+
88
+ it "returns the resized name given a modified image" do
89
+ name = SnapImage::ImageNameUtils.get_resized_image_name("12345678-1x1-0x0x1x1-2048x100-0.png", 1024, 50)
90
+ name.should eq "12345678-1x1-0x0x1x1-1024x50-0.png"
91
+ end
92
+ end
93
+
94
+ describe "#generate_basename" do
95
+ it "generates 8 random alphanumeric characters" do
96
+ SnapImage::ImageNameUtils.generate_basename.should match /^[a-z0-9]{8}$/
97
+ end
98
+ end
99
+
100
+ describe "#generate_image_name" do
101
+ it "generates a base image name without options" do
102
+ SnapImage::ImageNameUtils.generate_image_name(1024, 768, "png").should match /[a-z0-9]{8}-1024x768\.png/
103
+ end
104
+
105
+ it "generates a base image name with just a basename option" do
106
+ SnapImage::ImageNameUtils.generate_image_name(1024, 768, "png", basename: "test").should eq "test-1024x768.png"
107
+ end
108
+
109
+ it "generates a modified image name with options" do
110
+ SnapImage::ImageNameUtils.generate_image_name(
111
+ 1024,
112
+ 768,
113
+ "png",
114
+ basename: "image",
115
+ crop: {
116
+ x: 6,
117
+ y: 7,
118
+ width: 134,
119
+ height: 350
120
+ },
121
+ width: 640,
122
+ height: 480,
123
+ sharpen: true
124
+ ).should eq "image-1024x768-6x7x134x350-640x480-1.png"
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,71 @@
1
+ require "spec_helper"
2
+
3
+ describe SnapImage::Image do
4
+ before do
5
+ @image_path = File.join(RSpec.root, "support/assets/stub-300x200.png")
6
+ end
7
+
8
+ describe "#crop" do
9
+ before do
10
+ @image = SnapImage::Image.new
11
+ @image.set_image_from_path(@image_path)
12
+ @original_width = @image.width
13
+ @original_height = @image.height
14
+ end
15
+
16
+ it "returns the correctly cropped image" do
17
+ image = @image.crop(10, 30, 20, 30)
18
+ image.width.should eq 20
19
+ image.height.should eq 30
20
+ end
21
+
22
+ it "does not modify the original image" do
23
+ image = @image.crop(10, 30, 20, 30)
24
+ @image.width.should eq @original_width
25
+ @image.height.should eq @original_height
26
+ end
27
+ end
28
+
29
+ describe "#resize" do
30
+ before do
31
+ @image = SnapImage::Image.new
32
+ @image.set_image_from_path(@image_path)
33
+ @original_width = @image.width
34
+ @original_height = @image.height
35
+ end
36
+
37
+ it "raises an error when no height is specified and maintaining aspect ratio is false" do
38
+ expect { @image.resize(100, nil, false) }.should raise_error
39
+ end
40
+
41
+ it "returns an appropriately resized image when the width is larger or equal to the height" do
42
+ image = @image.resize(330)
43
+ image.width.should eq 330
44
+ image.height.should eq 220
45
+ end
46
+
47
+ it "returns an appropriately resized image when the width is less than the height" do
48
+ image = @image.resize(150)
49
+ image.width.should eq 150
50
+ image.height.should eq 100
51
+ end
52
+
53
+ it "returns an image that fits within the width/height while maintaining aspect ratio" do
54
+ image = @image.resize(150, 200)
55
+ image.width.should eq 150
56
+ image.height.should eq 100
57
+ end
58
+
59
+ it "returns a stretched image when not maintaining aspect ratio" do
60
+ image = @image.resize(100, 200, false)
61
+ image.width.should eq 100
62
+ image.height.should eq 200
63
+ end
64
+
65
+ it "does not modify the original image" do
66
+ image = @image.resize(100)
67
+ @image.width.should eq @original_width
68
+ @image.height.should eq @original_height
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+
3
+ describe SnapImage::Middleware do
4
+ before do
5
+ @env = { "PATH_INFO" => "/test"}
6
+ @app = double("app")
7
+ end
8
+
9
+ describe "#call" do
10
+ it "passes the call through to the rack app when the path does not match" do
11
+ @app.should_receive(:call).with(@env).and_return("app")
12
+ middleware = SnapImage::Middleware.new(@app, config: {})
13
+ middleware.call(@env).should eq "app"
14
+ end
15
+
16
+ it "passes the call through to the SnapImage Server" do
17
+ server = double("server")
18
+ server.should_receive(:call).and_return("server")
19
+ SnapImage::Server.stub(:new).and_return(server)
20
+
21
+ @app.should_not_receive(:call)
22
+
23
+ middleware = SnapImage::Middleware.new(@app, config: {}, path: "/test")
24
+ middleware.call(@env).should eq "server"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ require "spec_helper"
2
+
3
+ describe SnapImage::RequestFile do
4
+ describe "#type" do
5
+ it "returns the correct type" do
6
+ file = SnapImage::RequestFile.new({filename: "image.png"})
7
+ file.type.should eq "png"
8
+ end
9
+
10
+ it "returns jpg when the type is jpeg" do
11
+ file = SnapImage::RequestFile.new({filename: "image.jpeg"})
12
+ file.type.should eq "jpg"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,52 @@
1
+ require "spec_helper"
2
+
3
+ describe SnapImage::Request do
4
+ before do
5
+ @request = SnapImage::Request.new({})
6
+ end
7
+
8
+ describe "#bad_request?" do
9
+ it "returns true if the request is not a post" do
10
+ json = { action: "test", resource_identifier: "123" }.to_json
11
+ @request.stub(:post?).and_return(false)
12
+ @request.stub(:POST).and_return({"json" => json})
13
+ @request.bad_request?.should be_true
14
+ end
15
+
16
+ it "returns true if the request does not include json" do
17
+ @request.stub(:post?).and_return(true)
18
+ @request.stub(:POST).and_return({})
19
+ @request.bad_request?.should be_true
20
+ end
21
+
22
+ it "returns true if the request does not include an action" do
23
+ json = { resource_identifier: "123" }.to_json
24
+ @request.stub(:post?).and_return(true)
25
+ @request.stub(:POST).and_return({"json" => json})
26
+ @request.bad_request?.should be_true
27
+ end
28
+
29
+ it "returns true if the request does not include a resource_identifier" do
30
+ json = { action: "test" }.to_json
31
+ @request.stub(:post?).and_return(true)
32
+ @request.stub(:POST).and_return({"json" => json})
33
+ @request.bad_request?.should be_true
34
+ end
35
+
36
+ it "returns false if the request is valid" do
37
+ json = { action: "test", resource_identifier: "123" }.to_json
38
+ @request.stub(:post?).and_return(true)
39
+ @request.stub(:POST).and_return({"json" => json})
40
+ @request.bad_request?.should be_false
41
+ end
42
+ end
43
+
44
+ describe "#json" do
45
+ it "returns the json object" do
46
+ @request.stub(:bad_request?).and_return(false)
47
+ @request.stub(:POST).and_return({"json" => '{"data":"value"}'})
48
+ json = @request.json
49
+ json["data"].should eq "value"
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,33 @@
1
+ require "spec_helper"
2
+
3
+ describe SnapImage::Response do
4
+ before do
5
+ @response = SnapImage::Response.new
6
+ end
7
+
8
+ describe "#set_success" do
9
+ it "sets a default message" do
10
+ @response.set_success
11
+ @response.json[:message].should eq "Success"
12
+ end
13
+
14
+ it "merges in the info" do
15
+ @response.set_success(some: "thing")
16
+ @response.json[:some].should eq "thing"
17
+ end
18
+ end
19
+
20
+ describe "#finish" do
21
+ it "sets the body" do
22
+ @response.json = { status_code: 200 }
23
+ response = @response.finish
24
+ response[2].body.should eq ['{"status_code":200}']
25
+ end
26
+
27
+ it "sets the Content-Type" do
28
+ response = @response.finish
29
+ response[1]["Content-Type"].should eq "text/json"
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,67 @@
1
+ require "spec_helper"
2
+
3
+ describe SnapImage::ServerActions::Authorize do
4
+ before do
5
+ class TestServerActions
6
+ include SnapImage::ServerActions::Authorize
7
+
8
+ attr_accessor :config
9
+
10
+ def initialize(request)
11
+ @request = request
12
+ @config = {"security_salt" => "abc123"}
13
+ end
14
+ end
15
+
16
+ @request = double("request")
17
+ @actions = TestServerActions.new(@request)
18
+ end
19
+
20
+ describe "#token_available?" do
21
+ before do
22
+ @request.stub(:json).and_return({"client_security_token" => "abc123"})
23
+ end
24
+ it "returns true when role's token is set" do
25
+ @actions.token_available?(:client).should be_true
26
+ end
27
+
28
+ it "returns false when role's token is not set" do
29
+ @actions.token_available?(:server).should be_false
30
+ end
31
+ end
32
+
33
+ describe "#generate_tokens" do
34
+ before do
35
+ @request.stub(:json).and_return({"resource_identifier" => "123"})
36
+ end
37
+
38
+ it "generates three token" do
39
+ now = Time.now
40
+ yesterday = (now - 24*60*60).strftime("%Y-%m-%d")
41
+ today = now.strftime("%Y-%m-%d")
42
+ tomorrow = (now + 24*60*60).strftime("%Y-%m-%d")
43
+ yesterday_token = Digest::SHA1.hexdigest("client:#{yesterday}:abc123:123")
44
+ today_token = Digest::SHA1.hexdigest("client:#{today}:abc123:123")
45
+ tomorrow_token = Digest::SHA1.hexdigest("client:#{tomorrow}:abc123:123")
46
+ @actions.generate_tokens(:client).should eq [yesterday_token, today_token, tomorrow_token]
47
+ end
48
+ end
49
+
50
+ describe "#authorize" do
51
+ it "returns true when the security_salt is not set" do
52
+ @actions.config = {}
53
+ @actions.authorize(:client).should be_true
54
+ end
55
+
56
+ it "raises an error when the token is not available" do
57
+ @actions.stub(:token_available?).and_return(false)
58
+ expect { @actions.authorize(:client) }.should raise_error SnapImage::AuthorizationRequired
59
+ end
60
+
61
+ it "raises an error when the token does not match" do
62
+ @request.stub(:json).and_return({"client_security_token" => "abc123", "resource_identifier" => "123"})
63
+ @actions.stub(:token_available?).and_return(true)
64
+ expect { @actions.authorize(:client) }.should raise_error SnapImage::AuthorizationFailed
65
+ end
66
+ end
67
+ end