activeresource-persistent 0.0.1 → 0.1.0

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