simultaneous 0.2.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.
@@ -0,0 +1,242 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ describe Simultaneous::Server do
4
+ before do
5
+ Simultaneous.reset!
6
+ end
7
+
8
+ after do
9
+ FileUtils.rm(SOCKET) if File.exist?(SOCKET)
10
+ end
11
+
12
+ describe "task messages" do
13
+ it "should generate events in clients on the right domain" do
14
+ client1 = client2 = client3 = nil
15
+ result1 = result2 = result3 = nil
16
+ result4 = result5 = result6 = nil
17
+
18
+ EM.run {
19
+ Simultaneous::Server.start(SOCKET)
20
+
21
+ client1 = Simultaneous::Client.new("domain1", SOCKET)
22
+ client2 = Simultaneous::Client.new("domain1", SOCKET)
23
+ client3 = Simultaneous::Client.new("domain2", SOCKET)
24
+
25
+ command = Simultaneous::Command::ClientEvent.new("domain1", "a", "data")
26
+
27
+ client1.on_event(:a) { |event| result1 = [:a, event.data] }
28
+ client2.on_event(:a) { |event| result2 = [:a, event.data] }
29
+ client3.on_event(:a) { |event| result3 = [:a, event.data] }
30
+ client1.on_event(:b) { |event| result4 = [:b, event.data] }
31
+ client2.on_event(:b) { |event| result5 = [:b, event.data] }
32
+ client3.on_event(:b) { |event| result6 = [:b, event.data] }
33
+
34
+ $receive_count = 0
35
+
36
+ $test = proc {
37
+ result1.must_equal [:a, "data"]
38
+ result2.must_equal [:a, "data"]
39
+ result3.must_be_nil
40
+ result4.must_be_nil
41
+ result5.must_be_nil
42
+ result6.must_be_nil
43
+ EM.stop
44
+ }
45
+
46
+ def client1.notify!
47
+ super
48
+ $receive_count += 1
49
+ if $receive_count == 3
50
+ $test.call
51
+ end
52
+ end
53
+
54
+ def client2.notify!
55
+ super
56
+ $receive_count += 1
57
+ if $receive_count == 3
58
+ $test.call
59
+ end
60
+ end
61
+
62
+ def client3.notify!
63
+ super
64
+ $receive_count += 1
65
+ if $receive_count == 3
66
+ $test.call
67
+ end
68
+ end
69
+
70
+ Thread.new {
71
+ Simultaneous::Server.run(command)
72
+ }.join
73
+ }
74
+ end
75
+ end
76
+
77
+ describe "Task" do
78
+ it "should make it intact from client to process" do
79
+ Simultaneous.domain = "example.org"
80
+ Simultaneous.connection = SOCKET
81
+
82
+ default_params = { :param1 => "param1" }
83
+ env = { "ENV_PARAM" => "envparam" }
84
+ args = {:param2 => "param2"}
85
+ niceness = 10
86
+ task_uid = 9999
87
+ options = {
88
+ :nice => niceness
89
+ }
90
+ task = Simultaneous.add_task(:publish, "/path/to/binary", options, default_params, env)
91
+ command = Simultaneous::Command::Fire.new(task, args)
92
+ dump = command.dump
93
+ mock(command).dump { dump }
94
+ mock(Simultaneous::Command::Fire).new(task, args) { command }
95
+ mock(Simultaneous::Command).load(is_a(String)) { command }
96
+ mock(command).valid? { true }
97
+ mock(command).task_uid.twice { task_uid }
98
+
99
+ EM.run do
100
+ Simultaneous::Server.start(SOCKET)
101
+
102
+ mock(Process).detach(9999)
103
+
104
+ mock(command).fork do |block|
105
+ mock(command).daemonize(%[/path/to/binary --param1="param1" --param2="param2"], is_a(String))
106
+ mock(Process).setpriority(Process::PRIO_PROCESS, 0, niceness)
107
+ mock(Process::UID).change_privilege(task_uid)
108
+ mock(File).umask(0022)
109
+ mock(command).exec(%[/path/to/binary --param1="param1" --param2="param2"])
110
+ block.call
111
+
112
+ ENV["ENV_PARAM"].must_equal "envparam"
113
+ ENV[Simultaneous::ENV_DOMAIN].must_equal "example.org"
114
+ ENV[Simultaneous::ENV_TASK_NAME].must_equal "publish"
115
+ ENV[Simultaneous::ENV_CONNECTION].must_equal SOCKET
116
+ EM.stop
117
+ 9999
118
+ end
119
+
120
+ Thread.new do
121
+ Simultaneous.fire(:publish, args)
122
+ end.join
123
+ end
124
+ end
125
+
126
+ it "should report back to the server to set the task PID" do
127
+ pids = {}
128
+ pid = 99999
129
+ Simultaneous.domain = "example.com"
130
+ Simultaneous.connection = SOCKET
131
+
132
+
133
+ EM.run do
134
+ Simultaneous::Server.start(SOCKET)
135
+
136
+ ENV[Simultaneous::ENV_DOMAIN] = "example.com"
137
+ ENV[Simultaneous::ENV_TASK_NAME] = "publish"
138
+ ENV[Simultaneous::ENV_CONNECTION] = SOCKET
139
+
140
+ mock(Simultaneous::Task).pid { pid }
141
+ mock(Simultaneous::Server).pids { pids }
142
+ mock(pids).[]=("example.com/publish", pid) { EM.stop }
143
+
144
+ Thread.new do
145
+ class SimultaneousTask
146
+ include Simultaneous::Task
147
+ end
148
+ end.join
149
+ end
150
+ end
151
+
152
+ it "should be able to trigger messages on the client" do
153
+ Simultaneous.domain = "example2.com"
154
+ Simultaneous.connection = SOCKET
155
+
156
+
157
+ EM.run do
158
+ Simultaneous::Server.start(SOCKET)
159
+
160
+ ENV[Simultaneous::ENV_DOMAIN] = "example2.com"
161
+ ENV[Simultaneous::ENV_TASK_NAME] = "publish"
162
+ ENV[Simultaneous::ENV_CONNECTION] = SOCKET
163
+
164
+ c = Simultaneous::TaskClient.new("example2.com", SOCKET)
165
+ mock(Simultaneous::TaskClient).new { c }
166
+ mock(c).run(is_a(Simultaneous::Command::SetPid))
167
+ proxy(c).run(is_a(Simultaneous::Command::ClientEvent))
168
+ client = Simultaneous::Client.new("example2.com", SOCKET)
169
+
170
+ client.on_event("publish_status") { |event|
171
+ event.data.must_equal "completed"
172
+ EM.stop
173
+ }
174
+
175
+ Thread.new do
176
+ class SimultaneousTask
177
+ include Simultaneous::Task
178
+ def run
179
+ simultaneous_event("publish_status", "completed")
180
+ end
181
+ end
182
+ SimultaneousTask.new.run
183
+ end.join
184
+
185
+ end
186
+ end
187
+
188
+ it "should be able to kill task processes" do
189
+ pid = 99999
190
+ pids = {"example3.com/publish" => pid}
191
+ Simultaneous.domain = "example3.com"
192
+ Simultaneous.connection = SOCKET
193
+
194
+
195
+ EM.run do
196
+ Simultaneous::Server.start(SOCKET)
197
+
198
+ ENV[Simultaneous::ENV_DOMAIN] = "example3.com"
199
+ ENV[Simultaneous::ENV_TASK_NAME] = "publish"
200
+ ENV[Simultaneous::ENV_CONNECTION] = SOCKET
201
+
202
+ c = Simultaneous::TaskClient.new("example3.com", SOCKET)
203
+ mock(Simultaneous::TaskClient).new { c }
204
+ mock(c).run(is_a(Simultaneous::Command::SetPid))
205
+ proxy(c).run(is_a(Simultaneous::Command::Kill))
206
+
207
+ mock(Simultaneous::Task).pid { pid }
208
+ mock(Simultaneous::Server).pids { pids }
209
+
210
+ Thread.new do
211
+ class SimultaneousTask
212
+ include Simultaneous::Task
213
+ end
214
+ end.join
215
+
216
+ Thread.new do
217
+ mock(Process).kill("TERM", pid) { EM.stop }
218
+ Simultaneous.kill(:publish)
219
+ end.join
220
+ end
221
+ end
222
+
223
+ it "should divert STDOUT and STDERR to file and inform the server when finished" do
224
+ Simultaneous.domain = "example4.com"
225
+ Simultaneous.connection = SOCKET
226
+ logfile = "/tmp/log-#{$$}/#{$$}-example.log"
227
+ FileUtils.rm_f(logfile) if File.exists?(logfile)
228
+ EM.run do
229
+ Simultaneous::Server.start(SOCKET)
230
+ task = Simultaneous.add_task(:example, File.expand_path("../tasks/example.rb", __FILE__), {:logfile => logfile})
231
+ proxy(Simultaneous::Server).run(is_a(Simultaneous::Command::Fire))
232
+ mock(Simultaneous::Server).run(is_a(Simultaneous::Command::SetPid))
233
+ mock(Simultaneous::Server).run(is_a(Simultaneous::Command::ClientEvent))
234
+ mock(Simultaneous::Server).run(is_a(Simultaneous::Command::TaskComplete)) { EM.stop }
235
+ Simultaneous.fire(:example, { "param" => "value" })
236
+ end
237
+ assert(File.exist?(logfile), "Task should have output to #{logfile}")
238
+ File.read(logfile).must_equal %(--param=value\n)
239
+ FileUtils.rm_rf(File.dirname(logfile)) if File.exists?(logfile)
240
+ end
241
+ end
242
+ end
data/test/test_task.rb ADDED
@@ -0,0 +1,21 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ describe Simultaneous::TaskDescription do
4
+ it "should generate the right default logfile location" do
5
+ mock(Dir).pwd { "/application/current" }
6
+ task = Simultaneous::TaskDescription.new(:fish, "/path/to/fish")
7
+ task.logfile.must_equal "/application/current/log/fish-task.log"
8
+ end
9
+ it "should generate the right default logfile location" do
10
+ task = Simultaneous::TaskDescription.new(:fish, "/path/to/fish", {:logfile => "/var/log/fish.log"})
11
+ task.logfile.must_equal "/var/log/fish.log"
12
+ end
13
+ it "should generate the right default logfile location" do
14
+ task = Simultaneous::TaskDescription.new(:fish, "/path/to/fish", {:log => "/var/log/fish.log"})
15
+ task.logfile.must_equal "/var/log/fish.log"
16
+ end
17
+
18
+ it "should set the right pwd" do
19
+ flunk
20
+ end
21
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simultaneous
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Garry Hill
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-03 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: eventmachine
16
+ requirement: &70278663630360 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.0.0.beta.4
22
+ - - <
23
+ - !ruby/object:Gem::Version
24
+ version: '2.0'
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: *70278663630360
28
+ - !ruby/object:Gem::Dependency
29
+ name: rack
30
+ requirement: &70278663629460 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ! '>='
34
+ - !ruby/object:Gem::Version
35
+ version: '1.0'
36
+ - - <
37
+ - !ruby/object:Gem::Version
38
+ version: '2.0'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: *70278663629460
42
+ - !ruby/object:Gem::Dependency
43
+ name: rack-async
44
+ requirement: &70278663628360 !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ! '>='
48
+ - !ruby/object:Gem::Version
49
+ version: 0.0.1
50
+ - - <
51
+ - !ruby/object:Gem::Version
52
+ version: '2.0'
53
+ type: :runtime
54
+ prerelease: false
55
+ version_requirements: *70278663628360
56
+ - !ruby/object:Gem::Dependency
57
+ name: rr
58
+ requirement: &70278663626460 !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ~>
62
+ - !ruby/object:Gem::Version
63
+ version: 1.0.4
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: *70278663626460
67
+ description: Simultaneous is designed for the very specific use case of a small set
68
+ of users collaborating on editing a single website. Because of that it is optimised
69
+ for infrequent invocation of very long running publishing tasks and provides an
70
+ event based messaging system that allows launched tasks to communicate back to the
71
+ CMS web-server and for that server to then fire off update messages through HTML5
72
+ Server-Sent Events.
73
+ email: garry@magnetised.info
74
+ executables:
75
+ - simultaneous-server
76
+ - simultaneous-console
77
+ extensions: []
78
+ extra_rdoc_files:
79
+ - README
80
+ - LICENSE
81
+ files:
82
+ - Gemfile
83
+ - LICENSE
84
+ - README
85
+ - Rakefile
86
+ - bin/simultaneous-console
87
+ - bin/simultaneous-server
88
+ - lib/simultaneous.rb
89
+ - lib/simultaneous/broadcast_message.rb
90
+ - lib/simultaneous/client.rb
91
+ - lib/simultaneous/command.rb
92
+ - lib/simultaneous/command/client_event.rb
93
+ - lib/simultaneous/command/fire.rb
94
+ - lib/simultaneous/command/kill.rb
95
+ - lib/simultaneous/command/set_pid.rb
96
+ - lib/simultaneous/command/task_complete.rb
97
+ - lib/simultaneous/connection.rb
98
+ - lib/simultaneous/rack.rb
99
+ - lib/simultaneous/server.rb
100
+ - lib/simultaneous/task.rb
101
+ - lib/simultaneous/task_client.rb
102
+ - lib/simultaneous/task_description.rb
103
+ - simultaneous.gemspec
104
+ - test/helper.rb
105
+ - test/tasks/example.rb
106
+ - test/test_client.rb
107
+ - test/test_command.rb
108
+ - test/test_connection.rb
109
+ - test/test_faf.rb
110
+ - test/test_message.rb
111
+ - test/test_server.rb
112
+ - test/test_task.rb
113
+ homepage: http://spontaneouscms.org
114
+ licenses: []
115
+ post_install_message:
116
+ rdoc_options:
117
+ - --charset=UTF-8
118
+ require_paths:
119
+ - lib
120
+ required_ruby_version: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ! '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ requirements: []
133
+ rubyforge_project: simultaneous
134
+ rubygems_version: 1.8.10
135
+ signing_key:
136
+ specification_version: 2
137
+ summary: Simultaneous is the background task launcher used by Spontaneous CMS
138
+ test_files:
139
+ - test/test_client.rb
140
+ - test/test_command.rb
141
+ - test/test_connection.rb
142
+ - test/test_faf.rb
143
+ - test/test_message.rb
144
+ - test/test_server.rb
145
+ - test/test_task.rb