activeresource-persistent 0.0.1 → 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.
data/Gemfile CHANGED
@@ -1,3 +1,16 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
+
5
+ gem 'activeresource', '3.2.3'
6
+ gem 'net-http-persistent', '2.6'
7
+
8
+ group :test do
9
+ gem 'rspec', '2.8.0'
10
+ gem 'sinatra', '1.3.2'
11
+ gem 'posix-spawn', '0.3.6'
12
+ end
13
+
14
+ group :bundle do
15
+ gem 'passenger', '3.0.12'
16
+ end
data/README.md CHANGED
@@ -6,7 +6,7 @@ HTTP persistent connection support for ActiveResource.
6
6
 
7
7
  Add this line to your application's Gemfile:
8
8
 
9
- gem 'active_resource-persistent', :require => 'active_resource/persistent'
9
+ gem 'activeresource-persistent', :require => 'active_resource/persistent'
10
10
 
11
11
  And then execute:
12
12
 
@@ -14,7 +14,7 @@ And then execute:
14
14
 
15
15
  Or install it yourself as:
16
16
 
17
- $ gem install active_resource-persistent
17
+ $ gem install activeresource-persistent
18
18
 
19
19
  ## Usage
20
20
 
@@ -11,7 +11,7 @@ Gem::Specification.new do |gem|
11
11
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
12
12
  gem.name = "activeresource-persistent"
13
13
  gem.require_paths = ["lib"]
14
- gem.version = "0.0.1"
14
+ gem.version = "0.1.0"
15
15
 
16
16
  gem.add_runtime_dependency 'net-http-persistent', '>=2.5'
17
17
  gem.add_runtime_dependency 'activeresource', '>=2.3.0'
data/config.ru ADDED
@@ -0,0 +1,2 @@
1
+ Dir["spec/support/**/*.rb"].each { |f| load f }
2
+ run TestApplication.new
@@ -5,8 +5,11 @@ module ActiveResource
5
5
 
6
6
  protected
7
7
 
8
- def new_http
8
+ def new_http_with_persistent
9
9
  ActiveResource::Persistent::HTTP.new(site, proxy)
10
10
  end
11
+
12
+ alias_method :new_http_without_persistent, :new_http
13
+ alias_method :new_http, :new_http_with_persistent
11
14
  end
12
15
  end
@@ -8,6 +8,8 @@ module ActiveResource
8
8
  @site = site
9
9
  end
10
10
 
11
+ attr_reader :site
12
+
11
13
  def get(path, headers)
12
14
  req = Net::HTTP::Get.new(path, headers)
13
15
  request(@site, req)
data/public/.gitkeep ADDED
File without changes
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveResource::Connection do
4
+ let(:site) { TestServer.uri }
5
+
6
+ let(:instance) { described_class.new(site) }
7
+
8
+ describe "#http" do
9
+ subject { instance.send(:http) }
10
+ it "should be persistent" do
11
+ subject.should be_instance_of(ActiveResource::Persistent::HTTP)
12
+ subject.site.should == site
13
+ end
14
+ end
15
+
16
+ describe "#new_http" do
17
+ specify { instance.send(:new_http).should be_instance_of(ActiveResource::Persistent::HTTP) }
18
+ end
19
+
20
+ describe "#new_http_with_persistent" do
21
+ specify { instance.send(:new_http_with_persistent).should be_instance_of(ActiveResource::Persistent::HTTP) }
22
+ end
23
+
24
+ describe "#new_http_without_persistent" do
25
+ specify { instance.send(:new_http_without_persistent).should be_instance_of(Net::HTTP) }
26
+ end
27
+
28
+ context "request methods" do
29
+ let(:path) { '/inspect' }
30
+ let(:body) { 'HELLO WORLD' }
31
+ let(:headers) { { 'X_Header' => 'x_value' } }
32
+ let(:http_mock) { mock('HTTP MOCK') }
33
+ let(:response_mock) { mock('RESPONSE MOCK', :code => '200') }
34
+
35
+ describe "#head" do
36
+ it "should use ActiveResource::Persistent::HTTP#head" do
37
+ expected_headers = headers.update('Accept' => 'application/json')
38
+ instance.should_receive(:http).and_return(http_mock)
39
+ http_mock.should_receive(:head).with(path, expected_headers).and_return(response_mock)
40
+
41
+ instance.head(path, headers)
42
+ end
43
+ end
44
+
45
+ describe "#get" do
46
+ it "should use ActiveResource::Persistent::HTTP#get" do
47
+ expected_headers = headers.update('Accept' => 'application/json')
48
+ instance.should_receive(:http).and_return(http_mock)
49
+ http_mock.should_receive(:get).with(path, expected_headers).and_return(response_mock)
50
+
51
+ instance.get(path, headers)
52
+ end
53
+ end
54
+
55
+ describe "#delete" do
56
+ it "should use ActiveResource::Persistent::HTTP#delete" do
57
+ expected_headers = headers.update('Accept' => 'application/json')
58
+ instance.should_receive(:http).and_return(http_mock)
59
+ http_mock.should_receive(:delete).with(path, expected_headers).and_return(response_mock)
60
+
61
+ instance.delete(path, headers)
62
+ end
63
+ end
64
+
65
+ describe "#post" do
66
+ it "should use ActiveResource::Persistent::HTTP#post" do
67
+ expected_headers = headers.update('Content-Type' => 'application/json')
68
+ instance.should_receive(:http).and_return(http_mock)
69
+ http_mock.should_receive(:post).with(path, body, expected_headers).and_return(response_mock)
70
+
71
+ instance.post(path, body, headers)
72
+ end
73
+ end
74
+
75
+ describe "#put" do
76
+ it "should use ActiveResource::Persistent::HTTP#put" do
77
+ expected_headers = headers.update('Content-Type' => 'application/json')
78
+ instance.should_receive(:http).and_return(http_mock)
79
+ http_mock.should_receive(:put).with(path, body, expected_headers).and_return(response_mock)
80
+
81
+ instance.put(path, body, headers)
82
+ end
83
+ end
84
+ end
85
+
86
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ describe %q(
4
+ As Developer
5
+ I order to speed up my active resources usage
6
+ I want to use HTTP 1.1 keepalive feature
7
+ ) do
8
+
9
+ it "Retrieving one resource multiple times" do
10
+ ids = %w(101 202 303)
11
+ users = ids.map { |id| TestUser.find(id) }
12
+
13
+ users[0].id.should == ids[0]
14
+ users[1].id.should == ids[1]
15
+ users[2].id.should == ids[2]
16
+
17
+ TestHelper.logged_requests.size.should == 3
18
+ TestHelper.persistent_requests_logged?.should be_true
19
+ end
20
+
21
+ it "Retrieving two resources from the same site" do
22
+ user = TestUser.find("101")
23
+ post = TestPost.find("202")
24
+
25
+ user.id.should == "101"
26
+ post.id.should == "202"
27
+
28
+ TestHelper.logged_requests.size.should == 2
29
+ TestHelper.persistent_requests_logged?.should be_true
30
+ end
31
+
32
+ it "Delete different resources from the same site" do
33
+ TestUser.find("101").destroy
34
+ TestPost.find("202").destroy
35
+
36
+ TestHelper.logged_requests.size.should == 4
37
+ TestHelper.persistent_requests_logged?.should be_true
38
+ end
39
+
40
+ it "Updating different resources from the same site" do
41
+ user = TestUser.find("101").update_attribute(:username, "jack")
42
+ post = TestPost.find("202").update_attribute(:title, "hi")
43
+
44
+ TestHelper.logged_requests.size.should == 4
45
+ TestHelper.persistent_requests_logged?.should be_true
46
+ end
47
+
48
+
49
+ it "Creating different resources on the same site" do
50
+ user = TestUser.create(:username => "Bob")
51
+ post = TestPost.create(:title => "Hello Bob")
52
+
53
+ user.id.should_not be_blank
54
+ post.id.should_not be_blank
55
+
56
+ user.username.should == "Bob"
57
+ post.title.should == "Hello Bob"
58
+
59
+ TestHelper.logged_requests.size.should == 2
60
+ TestHelper.persistent_requests_logged?.should be_true
61
+ end
62
+ end
@@ -0,0 +1,77 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveResource::Persistent::HTTP do
4
+ describe "class" do
5
+ subject { described_class }
6
+ its(:superclass) { should == Net::HTTP::Persistent }
7
+ end
8
+
9
+ describe "instance" do
10
+ let(:site) { URI.parse('http://site.example.com:3000') }
11
+ let(:proxy) { URI.parse('http://proxy.example.com:8080') }
12
+
13
+ subject { described_class.new(site, proxy) }
14
+
15
+ it "should have site" do
16
+ subject.site.should == site
17
+ end
18
+
19
+ it "should have proxy_uri" do
20
+ subject.proxy_uri.should == proxy
21
+ end
22
+ end
23
+
24
+ context "request methods" do
25
+ let(:site) { TestServer.uri }
26
+ let(:instance) { described_class.new(site, nil) }
27
+
28
+ let(:path) { '/inspect/all?key=value' }
29
+ let(:body) { 'HELLO WORLD' }
30
+ let(:headers) { { 'X-AUTHORIZATION' => 'qwerty' } }
31
+
32
+ it "should HEAD data" do
33
+ @response = instance.head(path, headers)
34
+
35
+ @response.should be_instance_of(Net::HTTPOK)
36
+ @response.body.should be_nil
37
+ end
38
+
39
+ it "should GET data" do
40
+ @response = instance.get(path, headers)
41
+
42
+ expect_response('GET', nil)
43
+ end
44
+
45
+ it "should DELETE data" do
46
+ @response = instance.delete(path, headers)
47
+
48
+ expect_response('DELETE', nil)
49
+ end
50
+
51
+ it "should POST data" do
52
+ @response = instance.post(path, body, headers)
53
+
54
+ expect_response('POST', body)
55
+ end
56
+
57
+ it "should PUT data" do
58
+ @response = instance.put(path, body, headers)
59
+
60
+ expect_response('PUT', body)
61
+ end
62
+
63
+ protected
64
+
65
+ def expect_response(request_method, payload)
66
+ @response.should be_instance_of(Net::HTTPOK)
67
+
68
+ body = YAML.load(@response.body)
69
+
70
+ body['REQUEST_METHOD'].should == request_method
71
+ body['REQUEST_URI'].should == path
72
+ body['HTTP_X_AUTHORIZATION'].should == 'qwerty'
73
+ body['rack.input'].should == payload
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,22 @@
1
+ Bundler.setup
2
+
3
+ require 'active_resource/persistent'
4
+
5
+ Dir["spec/support/**/*.rb"].each { |f| load f }
6
+
7
+ RSpec.configure do |config|
8
+ config.before(:suite) do
9
+ TestServer.start
10
+
11
+ TestUser.site = TestServer.uri
12
+ TestPost.site = TestServer.uri
13
+ end
14
+
15
+ config.before(:each) do
16
+ TestIPC.clear
17
+ end
18
+
19
+ config.after(:suite) do
20
+ TestServer.stop
21
+ end
22
+ end
@@ -0,0 +1,127 @@
1
+ require 'sinatra'
2
+ require 'multi_json'
3
+
4
+ class TestApplication < Sinatra::Base
5
+ before do
6
+ TestHelper.log_request(env)
7
+ end
8
+
9
+ #
10
+ # User resources
11
+ #
12
+
13
+ get '/users/:id.json' do
14
+ id = params[:id]
15
+ data_halt({
16
+ 'id' => id,
17
+ 'username' => "jack_#{id}",
18
+ 'remote_port' => env['REMOTE_PORT']
19
+ })
20
+ end
21
+
22
+ get '/users.json' do
23
+ data_halt([
24
+ {
25
+ 'id' => 1,
26
+ 'username' => "alice",
27
+ 'remote_port' => env['REMOTE_PORT']
28
+ },
29
+ {
30
+ 'id' => 2,
31
+ 'username' => "bob",
32
+ 'remote_port' => env['REMOTE_PORT']
33
+ }
34
+ ])
35
+ end
36
+
37
+ post '/users.json' do
38
+ user = MultiJson.load(request.body)
39
+
40
+ id = Time.now.to_i
41
+
42
+ halt 202, { 'Location' => "/users/#{id}" }, ''
43
+ end
44
+
45
+ put '/users/:id.json' do
46
+ id = params[:id]
47
+ user = MultiJson.load(request.body)
48
+ data_halt(user)
49
+ end
50
+
51
+ delete '/users/:id.json' do
52
+ id = params[:id]
53
+ halt 200
54
+ end
55
+
56
+ #
57
+ # Post resources
58
+ #
59
+
60
+ get '/posts/:id.json' do
61
+ id = params[:id]
62
+
63
+ data_halt({
64
+ 'id' => id,
65
+ 'title' => "hello_world_#{id}",
66
+ 'remote_port' => env['REMOTE_PORT']
67
+ })
68
+ end
69
+
70
+ put '/posts/:id.json' do
71
+ id = params[:id]
72
+ post = MultiJson.load(request.body)
73
+ data_halt(post)
74
+ end
75
+
76
+ post '/posts.json' do
77
+ post = MultiJson.load(request.body)
78
+
79
+ id = Time.now.to_i
80
+
81
+ halt 202, { 'Location' => "/posts/#{id}" }, ''
82
+ end
83
+
84
+ delete '/posts/:id.json' do
85
+ id = params[:id]
86
+ halt 200
87
+ end
88
+
89
+ #
90
+ # Inspect other requests
91
+ #
92
+ head '/*' do nil end
93
+ get '/*' do env_halt end
94
+ delete '/*' do env_halt end
95
+ post '/*' do env_halt end
96
+ put '/*' do env_halt end
97
+
98
+ protected
99
+
100
+ def data_halt(data, status = 200)
101
+ content_type :json
102
+ body MultiJson.dump(data)
103
+ halt status
104
+ end
105
+
106
+ def env_halt
107
+ payload = {}
108
+
109
+ env.sort.each do |key, value|
110
+ case key
111
+ when 'rack.input'
112
+ while line = value.gets
113
+ data ||= ""
114
+ data << line
115
+ end
116
+ payload[key] = data
117
+ when /^rack\./
118
+ else
119
+ payload[key] = value
120
+ end
121
+ end
122
+
123
+ content_type :text
124
+ body payload.to_yaml
125
+ halt 200
126
+ end
127
+ end
@@ -0,0 +1,22 @@
1
+ module TestHelper
2
+ extend self
3
+
4
+ def log_request(env)
5
+ data = [
6
+ env['REMOTE_PORT'],
7
+ env['REQUEST_METHOD'],
8
+ env['REQUEST_URI']
9
+ ].join('|')
10
+
11
+ TestIPC.push(data)
12
+ end
13
+
14
+ def logged_requests
15
+ TestIPC.pull.map { |line| line.split('|') }
16
+ end
17
+
18
+ def persistent_requests_logged?
19
+ logged_requests.map { |line| line[0] }.uniq.size == 1
20
+ end
21
+
22
+ end
@@ -0,0 +1,19 @@
1
+ module TestIPC
2
+ extend self
3
+
4
+ def filename
5
+ @filename = File.expand_path('../../../tmp/test_ipc.text', __FILE__)
6
+ end
7
+
8
+ def clear
9
+ File.delete(filename) if File.exists?(filename)
10
+ end
11
+
12
+ def push(data)
13
+ File.open(filename, "a+") { |f| f.puts(data) }
14
+ end
15
+
16
+ def pull
17
+ File.exists?(filename) ? File.read(filename).split("\n") : []
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ require 'active_resource'
2
+
3
+ class TestUser < ActiveResource::Base
4
+ self.element_name = 'user'
5
+ end
6
+
7
+ class TestPost < ActiveResource::Base
8
+ self.element_name = 'post'
9
+ end
@@ -0,0 +1,40 @@
1
+ require 'socket'
2
+ require 'posix/spawn'
3
+
4
+ module TestServer
5
+ extend self
6
+
7
+ def host
8
+ 'localhost'
9
+ end
10
+
11
+ def port
12
+ 9292
13
+ end
14
+
15
+ def uri
16
+ URI.parse("http://#{host}:#{port}")
17
+ end
18
+
19
+ def pid
20
+ @pid
21
+ end
22
+
23
+ def start
24
+ @pid = POSIX::Spawn.spawn("passenger start --port #{port}", :out => 'test_server.output')
25
+ sleep(1)
26
+ end
27
+
28
+ def stop
29
+ Process.kill("TERM", pid) if pid
30
+ end
31
+
32
+ protected
33
+
34
+ def find_available_port
35
+ server = TCPServer.new('127.0.0.1', '9292')
36
+ server.addr[1]
37
+ ensure
38
+ server.close if server
39
+ end
40
+ end
metadata CHANGED
@@ -1,106 +1,97 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: activeresource-persistent
3
- version: !ruby/object:Gem::Version
4
- hash: 29
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 0
9
- - 1
10
- version: 0.0.1
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Andriy Yanko
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2012-04-19 00:00:00 +03:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
12
+ date: 2012-04-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
22
15
  name: net-http-persistent
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &16473480 !ruby/object:Gem::Requirement
25
17
  none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 9
30
- segments:
31
- - 2
32
- - 5
33
- version: "2.5"
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '2.5'
34
22
  type: :runtime
35
- version_requirements: *id001
36
- - !ruby/object:Gem::Dependency
37
- name: activeresource
38
23
  prerelease: false
39
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: *16473480
25
+ - !ruby/object:Gem::Dependency
26
+ name: activeresource
27
+ requirement: &16472560 !ruby/object:Gem::Requirement
40
28
  none: false
41
- requirements:
42
- - - ">="
43
- - !ruby/object:Gem::Version
44
- hash: 3
45
- segments:
46
- - 2
47
- - 3
48
- - 0
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
49
32
  version: 2.3.0
50
33
  type: :runtime
51
- version_requirements: *id002
34
+ prerelease: false
35
+ version_requirements: *16472560
52
36
  description: HTTP persistent connection support for ActiveResource
53
- email:
37
+ email:
54
38
  - andriy.yanko@gmail.com
55
39
  executables: []
56
-
57
40
  extensions: []
58
-
59
41
  extra_rdoc_files: []
60
-
61
- files:
42
+ files:
62
43
  - .gitignore
63
44
  - Gemfile
64
45
  - LICENSE
65
46
  - README.md
66
47
  - Rakefile
67
48
  - activeresource-persistent.gemspec
49
+ - config.ru
68
50
  - lib/active_resource/persistent.rb
69
51
  - lib/active_resource/persistent/connection.rb
70
52
  - lib/active_resource/persistent/http.rb
71
- has_rdoc: true
53
+ - public/.gitkeep
54
+ - spec/active_resource/connection_spec.rb
55
+ - spec/active_resource/integration_spec.rb
56
+ - spec/active_resource/persistent/http_spec.rb
57
+ - spec/spec_helper.rb
58
+ - spec/support/test_application.rb
59
+ - spec/support/test_helper.rb
60
+ - spec/support/test_ipc.rb
61
+ - spec/support/test_resources.rb
62
+ - spec/support/test_server.rb
72
63
  homepage: https://github.com/railsware/activeresource-persistent
73
64
  licenses: []
74
-
75
65
  post_install_message:
76
66
  rdoc_options: []
77
-
78
- require_paths:
67
+ require_paths:
79
68
  - lib
80
- required_ruby_version: !ruby/object:Gem::Requirement
69
+ required_ruby_version: !ruby/object:Gem::Requirement
81
70
  none: false
82
- requirements:
83
- - - ">="
84
- - !ruby/object:Gem::Version
85
- hash: 3
86
- segments:
87
- - 0
88
- version: "0"
89
- required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
76
  none: false
91
- requirements:
92
- - - ">="
93
- - !ruby/object:Gem::Version
94
- hash: 3
95
- segments:
96
- - 0
97
- version: "0"
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
98
81
  requirements: []
99
-
100
82
  rubyforge_project:
101
- rubygems_version: 1.5.2
83
+ rubygems_version: 1.8.10
102
84
  signing_key:
103
85
  specification_version: 3
104
86
  summary: HTTP persistent connection support for ActiveResource
105
- test_files: []
106
-
87
+ test_files:
88
+ - spec/active_resource/connection_spec.rb
89
+ - spec/active_resource/integration_spec.rb
90
+ - spec/active_resource/persistent/http_spec.rb
91
+ - spec/spec_helper.rb
92
+ - spec/support/test_application.rb
93
+ - spec/support/test_helper.rb
94
+ - spec/support/test_ipc.rb
95
+ - spec/support/test_resources.rb
96
+ - spec/support/test_server.rb
97
+ has_rdoc: