pandemic 0.5.4

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 (38) hide show
  1. data/MIT-LICENSE +22 -0
  2. data/Manifest +27 -0
  3. data/README.markdown +133 -0
  4. data/Rakefile +14 -0
  5. data/examples/client/client.rb +17 -0
  6. data/examples/client/constitution.txt +865 -0
  7. data/examples/client/pandemic_client.yml +3 -0
  8. data/examples/server/pandemic_server.yml +3 -0
  9. data/examples/server/word_count_server.rb +47 -0
  10. data/lib/pandemic.rb +42 -0
  11. data/lib/pandemic/client_side/cluster_connection.rb +194 -0
  12. data/lib/pandemic/client_side/config.rb +34 -0
  13. data/lib/pandemic/client_side/connection.rb +40 -0
  14. data/lib/pandemic/client_side/connection_proxy.rb +15 -0
  15. data/lib/pandemic/client_side/pandemize.rb +17 -0
  16. data/lib/pandemic/connection_pool.rb +194 -0
  17. data/lib/pandemic/mutex_counter.rb +50 -0
  18. data/lib/pandemic/requests_per_second.rb +31 -0
  19. data/lib/pandemic/server_side/client.rb +123 -0
  20. data/lib/pandemic/server_side/config.rb +74 -0
  21. data/lib/pandemic/server_side/handler.rb +31 -0
  22. data/lib/pandemic/server_side/peer.rb +211 -0
  23. data/lib/pandemic/server_side/processor.rb +90 -0
  24. data/lib/pandemic/server_side/request.rb +92 -0
  25. data/lib/pandemic/server_side/server.rb +285 -0
  26. data/lib/pandemic/util.rb +15 -0
  27. data/pandemic.gemspec +37 -0
  28. data/test/client_test.rb +87 -0
  29. data/test/connection_pool_test.rb +133 -0
  30. data/test/functional_test.rb +57 -0
  31. data/test/handler_test.rb +31 -0
  32. data/test/mutex_counter_test.rb +73 -0
  33. data/test/peer_test.rb +48 -0
  34. data/test/processor_test.rb +33 -0
  35. data/test/server_test.rb +171 -0
  36. data/test/test_helper.rb +24 -0
  37. data/test/util_test.rb +21 -0
  38. metadata +141 -0
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+
3
+ class HandlerTest < Test::Unit::TestCase
4
+ include TestHelper
5
+
6
+ context "with a basic echo processor" do
7
+ setup do
8
+ echo = Class.new do
9
+ def process(body)
10
+ body.reverse
11
+ end
12
+ end
13
+
14
+ @processor = Pandemic::ServerSide::Processor.new(echo)
15
+ end
16
+
17
+ should "have a running child process" do
18
+ assert !@processor.closed?
19
+ end
20
+
21
+ should "close running child" do
22
+ assert !@processor.closed?
23
+ @processor.close
24
+ assert @processor.closed?
25
+ end
26
+
27
+ should "echo back" do
28
+ 10.times do |i| # just to test the loop part
29
+ assert_equal "#{i} dlrow olleh", @processor.process("hello world #{i}")
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,171 @@
1
+ require 'test_helper'
2
+
3
+ class ServerTest < Test::Unit::TestCase
4
+ include TestHelper
5
+
6
+ context "without a peer list" do
7
+ setup do
8
+ Pandemic::ServerSide::Config.expects(:servers).returns(["localhost:4000"])
9
+ @server = Pandemic::ServerSide::Server.new("localhost:4000")
10
+ end
11
+
12
+ should "create a peer connection when a unknown peer tries to connect" do
13
+ ignore_threads = Thread.list
14
+ @tcpserver = mock()
15
+ TCPServer.expects(:new).with("localhost", 4000).returns(@tcpserver)
16
+
17
+ @conn = mock()
18
+ @conn.stubs(:peeraddr => ['','','',''])
19
+ @tcpserver.expects(:accept).twice.returns(@conn).then.raises(Pandemic::ServerSide::Server::StopServer)
20
+ peer = mock()
21
+ peer.stubs(:add_incoming_connection)
22
+ @conn.expects(:setsockopt).with(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
23
+
24
+ @conn.expects(:gets).returns("SERVER localhost:4001\n")
25
+ Pandemic::ServerSide::Peer.expects(:new).with("localhost:4001", is_a(Pandemic::ServerSide::Server)).returns(peer)
26
+ @tcpserver.expects(:close)
27
+ peer.stubs(:disconnect) # the StopServer signal could be called before the peer is added. race case not important for this test
28
+
29
+ @server.handler = mock(:new)
30
+ @server.start
31
+ wait_for_threads(ignore_threads)
32
+ end
33
+ end
34
+
35
+ should "create a pid file" do
36
+ ignore_threads = Thread.list
37
+
38
+ Pandemic::ServerSide::Config.expects(:pid_file).at_least_once.returns("test/pandemic.pid")
39
+ Pandemic::ServerSide::Config.expects(:servers).at_least_once.returns([])
40
+
41
+ @tcpserver = mock()
42
+ TCPServer.expects(:new).with("localhost", 4000).returns(@tcpserver)
43
+
44
+ file = mock()
45
+ File.expects(:open).with("test/pandemic.pid", "w").yields(file)
46
+ file.expects(:write).with(Process.pid)
47
+ File.expects(:chmod)
48
+ File.expects(:exists?).with("test/pandemic.pid").returns(true)
49
+ File.expects(:unlink).with("test/pandemic.pid")
50
+
51
+ @tcpserver.expects(:accept).once.raises(Pandemic::ServerSide::Server::StopServer)
52
+
53
+ @tcpserver.expects(:close)
54
+
55
+ @server = Pandemic::ServerSide::Server.new("localhost:4000")
56
+
57
+ @server.handler = mock(:new)
58
+ @server.start
59
+ wait_for_threads(ignore_threads)
60
+ end
61
+
62
+ should "initialize peers" do
63
+ Pandemic::ServerSide::Config.expects(:servers).returns(["localhost:4000", "localhost:4001"])
64
+ Pandemic::ServerSide::Peer.expects(:new).with("localhost:4001", is_a(Pandemic::ServerSide::Server))
65
+ @server = Pandemic::ServerSide::Server.new("localhost:4000")
66
+ end
67
+
68
+ context "with a server" do
69
+ setup do
70
+ Pandemic::ServerSide::Config.expects(:servers).returns(["localhost:4000", "localhost:4001"])
71
+ @peer = mock()
72
+ Pandemic::ServerSide::Peer.expects(:new).with("localhost:4001", is_a(Pandemic::ServerSide::Server)).returns(@peer)
73
+ @server = Pandemic::ServerSide::Server.new("localhost:4000")
74
+ end
75
+
76
+ should "start a TCPServer, and connect to peers" do
77
+ ignore_threads = Thread.list
78
+ @tcpserver = mock()
79
+ TCPServer.expects(:new).with("localhost", 4000).returns(@tcpserver)
80
+ @peer.expects(:connect).once
81
+ @tcpserver.expects(:accept).twice.returns(nil).then.raises(Pandemic::ServerSide::Server::StopServer)
82
+ @tcpserver.expects(:close)
83
+ @peer.expects(:disconnect)
84
+ @server.handler = mock(:new)
85
+ @server.start
86
+ wait_for_threads(ignore_threads)
87
+ end
88
+
89
+ should "create a new client object for a client connection" do
90
+ ignore_threads = Thread.list
91
+
92
+ @tcpserver = mock()
93
+ TCPServer.expects(:new).with("localhost", 4000).returns(@tcpserver)
94
+ @peer.expects(:connect).once
95
+
96
+ @conn = mock()
97
+ @conn.stubs(:peeraddr => ['','','',''])
98
+ @tcpserver.expects(:accept).twice.returns(@conn).then.raises(Pandemic::ServerSide::Server::StopServer)
99
+ client = mock()
100
+ @conn.expects(:setsockopt).with(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
101
+
102
+ Pandemic::ServerSide::Client.expects(:new).with(@conn, @server).returns(client)
103
+
104
+
105
+ @conn.expects(:gets).returns("CLIENT\n")
106
+ @tcpserver.expects(:close)
107
+ @peer.expects(:disconnect)
108
+ client.expects(:listen).returns(client)
109
+ client.expects(:close).at_most_once # optional due to threaded nature, this may not actually happen
110
+ @server.handler = mock(:new)
111
+ @server.start
112
+ wait_for_threads(ignore_threads)
113
+ end
114
+
115
+ should "connect with the corresponding peer object" do
116
+ ignore_threads = Thread.list
117
+ @tcpserver = mock()
118
+ TCPServer.expects(:new).with("localhost", 4000).returns(@tcpserver)
119
+ @peer.expects(:connect).once
120
+
121
+ @conn = mock()
122
+ @conn.stubs(:peeraddr => ['','','',''])
123
+ @tcpserver.expects(:accept).twice.returns(@conn).then.raises(Pandemic::ServerSide::Server::StopServer)
124
+ @tcpserver.expects(:close)
125
+ @peer.expects(:disconnect)
126
+
127
+ @conn.expects(:setsockopt).with(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
128
+ @conn.expects(:gets).returns("SERVER localhost:4001\n")
129
+
130
+ @peer.expects(:host).returns("localhost")
131
+ @peer.expects(:port).returns(4001)
132
+ @peer.expects(:add_incoming_connection).with(@conn)
133
+ @server.handler = mock(:new)
134
+
135
+ @server.start
136
+ wait_for_threads(ignore_threads)
137
+ end
138
+
139
+ should "call process on handler" do
140
+ handler_class = mock()
141
+ handler = mock()
142
+ handler_class.expects(:new).once.returns(handler)
143
+ handler.expects(:process).with("body")
144
+ @server.handler = handler_class
145
+ @server.process("body")
146
+ end
147
+
148
+ should "map request, distribute to peers, and reduce" do
149
+ handler_class = mock()
150
+ handler = mock()
151
+ handler_class.expects(:new).once.returns(handler)
152
+ request = mock()
153
+ request.stubs(:hash => "abcddef134123")
154
+ @peer.expects(:connected?).returns(true)
155
+ handler.expects(:partition).with(request, is_a(Hash)).returns({"localhost:4000" => "1", "localhost:4001" => "2"})
156
+ request.expects(:max_responses=).with(2)
157
+ @peer.expects(:client_request).with(request, "2")
158
+
159
+ handler.expects(:process).with("1").returns("2")
160
+ request.expects(:add_response).with("2")
161
+
162
+ request.expects(:wait_for_responses).once
163
+ handler.expects(:reduce).with(request)
164
+
165
+ @server.handler = handler_class
166
+
167
+ @server.handle_client_request(request)
168
+ # wait_for_threads
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,24 @@
1
+ TEST_DIR = File.dirname(__FILE__)
2
+ %w(lib test).each do |dir|
3
+ $LOAD_PATH.unshift "#{TEST_DIR}/../#{dir}"
4
+ end
5
+
6
+ require 'rubygems'
7
+ require 'test/unit'
8
+ require 'pandemic'
9
+ require 'shoulda'
10
+ require 'mocha'
11
+
12
+
13
+ blackhole = StringIO.new
14
+ $pandemic_logger = Logger.new(blackhole)
15
+
16
+ module TestHelper
17
+ class TestException < Exception; end
18
+ def wait_for_threads(ignore = [Thread.current])
19
+ Thread.list.each do |thread|
20
+ next if ignore.include?(thread)
21
+ thread.join
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ require 'test_helper'
2
+
3
+ class UtilTest < Test::Unit::TestCase
4
+ context "with the module methods" do
5
+ setup do
6
+ @util = Object.new
7
+ @util.extend(Pandemic::Util)
8
+ end
9
+
10
+ should "parse out host and port" do
11
+ assert_equal ["localhost", 4000], @util.host_port("localhost:4000")
12
+ end
13
+
14
+ should "include the monitor mixin" do
15
+ object = Object.new
16
+ assert !object.respond_to?(:synchronize)
17
+ @util.with_mutex(object)
18
+ assert object.respond_to?(:synchronize)
19
+ end
20
+ end
21
+ end
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pandemic
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.4
5
+ platform: ruby
6
+ authors:
7
+ - Arya Asemanfar
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-09-07 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: shoulda
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: mocha
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ description: A framework for distributing work for real-time services and offline tasks.
36
+ email: aryaasemanfar@gmail.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - lib/pandemic/client_side/cluster_connection.rb
43
+ - lib/pandemic/client_side/config.rb
44
+ - lib/pandemic/client_side/connection.rb
45
+ - lib/pandemic/client_side/connection_proxy.rb
46
+ - lib/pandemic/client_side/pandemize.rb
47
+ - lib/pandemic/connection_pool.rb
48
+ - lib/pandemic/mutex_counter.rb
49
+ - lib/pandemic/requests_per_second.rb
50
+ - lib/pandemic/server_side/client.rb
51
+ - lib/pandemic/server_side/config.rb
52
+ - lib/pandemic/server_side/handler.rb
53
+ - lib/pandemic/server_side/peer.rb
54
+ - lib/pandemic/server_side/processor.rb
55
+ - lib/pandemic/server_side/request.rb
56
+ - lib/pandemic/server_side/server.rb
57
+ - lib/pandemic/util.rb
58
+ - lib/pandemic.rb
59
+ - README.markdown
60
+ files:
61
+ - examples/client/client.rb
62
+ - examples/client/constitution.txt
63
+ - examples/client/pandemic_client.yml
64
+ - examples/server/pandemic_server.yml
65
+ - examples/server/word_count_server.rb
66
+ - lib/pandemic/client_side/cluster_connection.rb
67
+ - lib/pandemic/client_side/config.rb
68
+ - lib/pandemic/client_side/connection.rb
69
+ - lib/pandemic/client_side/connection_proxy.rb
70
+ - lib/pandemic/client_side/pandemize.rb
71
+ - lib/pandemic/connection_pool.rb
72
+ - lib/pandemic/mutex_counter.rb
73
+ - lib/pandemic/requests_per_second.rb
74
+ - lib/pandemic/server_side/client.rb
75
+ - lib/pandemic/server_side/config.rb
76
+ - lib/pandemic/server_side/handler.rb
77
+ - lib/pandemic/server_side/peer.rb
78
+ - lib/pandemic/server_side/processor.rb
79
+ - lib/pandemic/server_side/request.rb
80
+ - lib/pandemic/server_side/server.rb
81
+ - lib/pandemic/util.rb
82
+ - lib/pandemic.rb
83
+ - Manifest
84
+ - MIT-LICENSE
85
+ - pandemic.gemspec
86
+ - Rakefile
87
+ - README.markdown
88
+ - test/client_test.rb
89
+ - test/connection_pool_test.rb
90
+ - test/functional_test.rb
91
+ - test/handler_test.rb
92
+ - test/mutex_counter_test.rb
93
+ - test/peer_test.rb
94
+ - test/processor_test.rb
95
+ - test/server_test.rb
96
+ - test/test_helper.rb
97
+ - test/util_test.rb
98
+ has_rdoc: true
99
+ homepage: https://github.com/arya/pandemic/
100
+ licenses: []
101
+
102
+ post_install_message:
103
+ rdoc_options:
104
+ - --line-numbers
105
+ - --inline-source
106
+ - --title
107
+ - Pandemic
108
+ - --main
109
+ - README.markdown
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: "0"
117
+ version:
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: "1.2"
123
+ version:
124
+ requirements: []
125
+
126
+ rubyforge_project: pandemic
127
+ rubygems_version: 1.3.4
128
+ signing_key:
129
+ specification_version: 3
130
+ summary: A framework for distributing work for real-time services and offline tasks.
131
+ test_files:
132
+ - test/client_test.rb
133
+ - test/connection_pool_test.rb
134
+ - test/functional_test.rb
135
+ - test/handler_test.rb
136
+ - test/mutex_counter_test.rb
137
+ - test/peer_test.rb
138
+ - test/processor_test.rb
139
+ - test/server_test.rb
140
+ - test/test_helper.rb
141
+ - test/util_test.rb