snapimage 0.0.1

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 (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