mt-libuv 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.gitmodules +6 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +24 -0
  6. data/Gemfile +9 -0
  7. data/LICENSE +24 -0
  8. data/README.md +195 -0
  9. data/Rakefile +31 -0
  10. data/ext/README.md +6 -0
  11. data/ext/Rakefile +28 -0
  12. data/lib/mt-libuv/async.rb +51 -0
  13. data/lib/mt-libuv/check.rb +59 -0
  14. data/lib/mt-libuv/coroutines.rb +79 -0
  15. data/lib/mt-libuv/dns.rb +98 -0
  16. data/lib/mt-libuv/error.rb +88 -0
  17. data/lib/mt-libuv/ext/ext.rb +322 -0
  18. data/lib/mt-libuv/ext/platform/darwin_x64.rb +61 -0
  19. data/lib/mt-libuv/ext/platform/unix.rb +69 -0
  20. data/lib/mt-libuv/ext/platform/windows.rb +83 -0
  21. data/lib/mt-libuv/ext/tasks/mac.rb +24 -0
  22. data/lib/mt-libuv/ext/tasks/unix.rb +42 -0
  23. data/lib/mt-libuv/ext/tasks/win.rb +29 -0
  24. data/lib/mt-libuv/ext/tasks.rb +27 -0
  25. data/lib/mt-libuv/ext/types.rb +253 -0
  26. data/lib/mt-libuv/fiber_pool.rb +83 -0
  27. data/lib/mt-libuv/file.rb +309 -0
  28. data/lib/mt-libuv/filesystem.rb +263 -0
  29. data/lib/mt-libuv/fs_event.rb +37 -0
  30. data/lib/mt-libuv/handle.rb +108 -0
  31. data/lib/mt-libuv/idle.rb +59 -0
  32. data/lib/mt-libuv/mixins/accessors.rb +41 -0
  33. data/lib/mt-libuv/mixins/assertions.rb +25 -0
  34. data/lib/mt-libuv/mixins/fs_checks.rb +96 -0
  35. data/lib/mt-libuv/mixins/listener.rb +69 -0
  36. data/lib/mt-libuv/mixins/net.rb +42 -0
  37. data/lib/mt-libuv/mixins/resource.rb +30 -0
  38. data/lib/mt-libuv/mixins/stream.rb +276 -0
  39. data/lib/mt-libuv/pipe.rb +217 -0
  40. data/lib/mt-libuv/prepare.rb +59 -0
  41. data/lib/mt-libuv/q.rb +475 -0
  42. data/lib/mt-libuv/reactor.rb +567 -0
  43. data/lib/mt-libuv/signal.rb +62 -0
  44. data/lib/mt-libuv/spawn.rb +113 -0
  45. data/lib/mt-libuv/tcp.rb +465 -0
  46. data/lib/mt-libuv/timer.rb +107 -0
  47. data/lib/mt-libuv/tty.rb +42 -0
  48. data/lib/mt-libuv/udp.rb +302 -0
  49. data/lib/mt-libuv/version.rb +5 -0
  50. data/lib/mt-libuv/work.rb +86 -0
  51. data/lib/mt-libuv.rb +80 -0
  52. data/mt-libuv.gemspec +62 -0
  53. data/spec/async_spec.rb +67 -0
  54. data/spec/coroutines_spec.rb +121 -0
  55. data/spec/cpu_spec.rb +10 -0
  56. data/spec/defer_spec.rb +906 -0
  57. data/spec/dns_spec.rb +110 -0
  58. data/spec/dsl_spec.rb +43 -0
  59. data/spec/filesystem_spec.rb +270 -0
  60. data/spec/idle_spec.rb +44 -0
  61. data/spec/pipe_spec.rb +151 -0
  62. data/spec/spawn_spec.rb +119 -0
  63. data/spec/tcp_spec.rb +272 -0
  64. data/spec/test.sh +4 -0
  65. data/spec/test_fail.sh +3 -0
  66. data/spec/test_read.sh +3 -0
  67. data/spec/timer_spec.rb +14 -0
  68. data/spec/udp_spec.rb +73 -0
  69. data/spec/zen_spec.rb +34 -0
  70. metadata +196 -0
@@ -0,0 +1,119 @@
1
+ require 'mt-libuv'
2
+
3
+ describe MTLibuv::Spawn do
4
+ describe 'basic spawn of external process' do
5
+ it "should accept arguments and return an termination signal code" do
6
+ @reactor = MTLibuv::Reactor.new
7
+ @log = []
8
+ @reactor.run { |reactor|
9
+ begin
10
+ p = MTLibuv::Spawn.new(reactor, './spec/test.sh', args: ['arg1', 'arg2'], env: ['SOME_VAR=123'])
11
+ p.stdout.progress do |data|
12
+ @log << data
13
+ end
14
+ p.stdout.start_read
15
+ @log << p.value
16
+ rescue => e
17
+ @log << e
18
+ @reactor.stop
19
+ end
20
+ }
21
+
22
+ term_signal = @log.pop
23
+ expect(term_signal).to be(0)
24
+
25
+ expect(@log[0]).to eq("123\narg1\narg2\n")
26
+ end
27
+
28
+ it "should return termination signal if exit code was 0" do
29
+ @reactor = MTLibuv::Reactor.new
30
+ @log = []
31
+ @reactor.run { |reactor|
32
+ begin
33
+ p = MTLibuv::Spawn.new(reactor, './spec/test.sh', args: ['arg1', 'arg2'], env: ['SOME_VAR=123'])
34
+ p.kill
35
+ p.stdout.progress do |data|
36
+ @log << data
37
+ end
38
+ p.stdout.start_read
39
+ @log << p.value
40
+ rescue => e
41
+ @log << e
42
+ @reactor.stop
43
+ end
44
+ }
45
+
46
+ term_signal = @log.pop
47
+ expect(term_signal).to be(2)
48
+ expect(@log[0]).to be(nil)
49
+ end
50
+
51
+ it "should fail if exit code was not 0 and read output from stderr" do
52
+ @reactor = MTLibuv::Reactor.new
53
+ @log = []
54
+ @reactor.run { |reactor|
55
+ begin
56
+ p = MTLibuv::Spawn.new(reactor, './spec/test_fail.sh')
57
+ p.stderr.progress do |data|
58
+ @log << data
59
+ end
60
+ p.stderr.start_read
61
+ @log << p.value
62
+ rescue => e
63
+ @log << e
64
+ @reactor.stop
65
+ end
66
+ }
67
+
68
+ stderr = @log[0]
69
+ e = @log[1]
70
+ expect(e.class).to be(::MTLibuv::Error::ProcessExitCode)
71
+ expect(e.exit_status).to be(1)
72
+ expect(e.term_signal).to be(0)
73
+ expect(stderr.length).to be > 0
74
+ end
75
+
76
+ it "should be interactive" do
77
+ @reactor = MTLibuv::Reactor.new
78
+ @log = []
79
+ @reactor.run { |reactor|
80
+ begin
81
+ p = MTLibuv::Spawn.new(reactor, './spec/test_read.sh')
82
+ p.stdout.progress do |data|
83
+ @log << data
84
+ end
85
+ p.stdout.start_read
86
+ p.stdin.write("2017\n")
87
+ @log << p.value
88
+ rescue => e
89
+ @log << e
90
+ @reactor.stop
91
+ end
92
+ }
93
+
94
+ term_signal = @log.pop
95
+ expect(term_signal).to be(0)
96
+
97
+ expect(@log[0]).to eq("you entered 2017 - sweet\n")
98
+ end
99
+
100
+ it "should support inheriting parent processes streams" do
101
+ @reactor = MTLibuv::Reactor.new
102
+ @log = []
103
+ @reactor.run { |reactor|
104
+ begin
105
+ p = MTLibuv::Spawn.new(reactor, './spec/test.sh', args: ['arg1', 'arg2'], env: ['SOME_VAR=123'], mode: :inherit)
106
+ @log << p.stdout
107
+ @log << p.value
108
+ rescue => e
109
+ @log << e
110
+ @reactor.stop
111
+ end
112
+ }
113
+
114
+ term_signal = @log.pop
115
+ expect(term_signal).to be(0)
116
+ expect(@log[0]).to be(nil)
117
+ end
118
+ end
119
+ end
data/spec/tcp_spec.rb ADDED
@@ -0,0 +1,272 @@
1
+ require 'mt-libuv'
2
+ require 'thread'
3
+
4
+
5
+ describe MTLibuv::TCP do
6
+ before :each do
7
+ @log = []
8
+ @general_failure = []
9
+
10
+ @reactor = MTLibuv::Reactor.new
11
+ @server = @reactor.tcp
12
+ @client = @reactor.tcp
13
+ @timeout = @reactor.timer do
14
+ @reactor.stop
15
+ @reactor2.stop if @reactor2
16
+ @general_failure << "test timed out"
17
+ end
18
+ @timeout.start(5000)
19
+
20
+ @reactor.all(@server, @client, @timeout).catch do |reason|
21
+ @general_failure << reason.inspect
22
+ end
23
+
24
+
25
+ @pipefile = "/tmp/test-pipe.pipe"
26
+ @reactor.notifier do |error, context|
27
+ begin
28
+ @general_failure << "Log called: #{context}\n#{error.message}\n#{error.backtrace.join("\n") if error.backtrace}\n"
29
+ rescue Exception => e
30
+ @general_failure << "error in logger #{e.inspect}"
31
+ end
32
+ end
33
+
34
+ begin
35
+ File.unlink(@pipefile)
36
+ rescue
37
+ end
38
+ end
39
+
40
+ describe 'basic client server' do
41
+ it "should send a ping and return a pong", :network => true do
42
+ @reactor.run { |reactor|
43
+ @server.bind('127.0.0.1', 34567) do |client|
44
+ client.progress do |data|
45
+ @log << data
46
+
47
+ client.write('pong')
48
+ end
49
+ client.start_read
50
+ end
51
+
52
+ # catch errors
53
+ @server.catch do |reason|
54
+ @general_failure << reason.inspect
55
+ end
56
+
57
+ # start listening
58
+ @server.listen(1024)
59
+
60
+
61
+
62
+ # connect client to server
63
+ @client.connect('127.0.0.1', 34567) do |client|
64
+ client.progress do |data|
65
+ @log << data
66
+
67
+ @client.shutdown
68
+ end
69
+
70
+ @client.start_read
71
+ @client.write('ping')
72
+ end
73
+
74
+ # catch errors
75
+ @client.catch do |reason|
76
+ @general_failure << reason.inspect
77
+ end
78
+
79
+ # close the handle
80
+ @client.finally do
81
+ @server.close
82
+ @reactor.stop
83
+ end
84
+ }
85
+
86
+ expect(@general_failure).to eq([])
87
+ expect(@log).to eq(['ping', 'pong'])
88
+ end
89
+
90
+ it "should work with coroutines", :network => true do
91
+ @reactor.run { |reactor|
92
+ @server.bind('127.0.0.1', 34567) do |client|
93
+ client.progress do |data|
94
+ @log << data
95
+
96
+ client.write('pong')
97
+ end
98
+ client.start_read
99
+ end
100
+
101
+ # catch errors
102
+ @server.catch do |reason|
103
+ @general_failure << reason.inspect
104
+ end
105
+
106
+ # start listening
107
+ @server.listen(1024)
108
+
109
+ # connect client to server
110
+ @client.progress do |data|
111
+ @log << data
112
+
113
+ addrinfo = @reactor.lookup('127.0.0.1')
114
+ @log << addrinfo[0][0]
115
+
116
+ @client.shutdown
117
+ end
118
+ # catch errors
119
+ @client.catch do |reason|
120
+ @general_failure << reason.inspect
121
+ end
122
+
123
+ # close the handle
124
+ @client.finally do
125
+ @server.close
126
+ @reactor.stop
127
+ end
128
+ @client.connect('127.0.0.1', 34567)
129
+ @client.start_read
130
+ @client.write('ping')
131
+ }
132
+
133
+ expect(@general_failure).to eq([])
134
+ expect(@log).to eq(['ping', 'pong', '127.0.0.1'])
135
+ end
136
+
137
+ it "should quack a bit like an IO object", :network => true do
138
+ @reactor.run { |reactor|
139
+ @server.bind('127.0.0.1', 34567) do |client|
140
+ @log << client.read(4)
141
+ client.write('pong')
142
+ end
143
+
144
+ # catch errors
145
+ @server.catch do |reason|
146
+ @general_failure << reason.inspect
147
+ end
148
+
149
+ # start listening
150
+ @server.listen(1024)
151
+
152
+ # catch errors
153
+ @client.catch do |reason|
154
+ @general_failure << reason.inspect
155
+ end
156
+
157
+ # close the handle
158
+ @client.finally do
159
+ @server.close
160
+ @reactor.stop
161
+ end
162
+ @client.connect('127.0.0.1', 34567)
163
+ @client.write('ping')
164
+ @log << @client.read(4)
165
+ addrinfo = @reactor.lookup('127.0.0.1')
166
+ @log << addrinfo[0][0]
167
+ @client.shutdown
168
+ }
169
+
170
+ expect(@general_failure).to eq([])
171
+ expect(@log).to eq(['ping', 'pong', '127.0.0.1'])
172
+ end
173
+ end
174
+
175
+ it "should handle requests on different threads", :network => true do
176
+ @sync = Mutex.new
177
+
178
+ @reactor.run { |reactor|
179
+ @remote = nil
180
+ @server.bind('127.0.0.1', 45678) do |client|
181
+ @remote.write2(client)
182
+ end
183
+
184
+ # catch errors
185
+ @server.catch do |reason|
186
+ @general_failure << reason.inspect
187
+ end
188
+
189
+
190
+ @pipeserve = @reactor.pipe(true)
191
+ @pipeserve.bind(@pipefile) do |client|
192
+ @remote = client
193
+
194
+ # start listening on TCP server
195
+ @server.listen(1024)
196
+
197
+ # connect client to server
198
+ @client.connect('127.0.0.1', 45678) do |client|
199
+ client.progress do |data|
200
+ @sync.synchronize {
201
+ @log << data
202
+ }
203
+ @client.shutdown
204
+ end
205
+
206
+ @client.start_read
207
+ @client.write('ping')
208
+ end
209
+
210
+ @pipeserve.getsockname
211
+ end
212
+
213
+ # start listening
214
+ @pipeserve.listen(1024)
215
+
216
+
217
+
218
+ # catch errors
219
+ @client.catch do |reason|
220
+ @general_failure << reason.inspect
221
+ end
222
+
223
+ # close the handle
224
+ @client.finally do
225
+ @server.close
226
+ @pipeserve.close
227
+ end
228
+
229
+
230
+
231
+ Thread.new do
232
+ @reactor2 = MTLibuv::Reactor.new
233
+ @reactor2.notifier do |error, context|
234
+ begin
235
+ @general_failure << "Log called: #{context}\n#{error.message}\n#{error.backtrace.join("\n") if error.backtrace}\n"
236
+ rescue Exception
237
+ @general_failure << "error in logger #{e.inspect}"
238
+ end
239
+ end
240
+ @pipeclient = @reactor2.pipe(true)
241
+
242
+
243
+ @reactor2.run do |reactor|
244
+ # connect client to server
245
+ @pipeclient.connect(@pipefile) do |client|
246
+ @pipeclient.progress do |data|
247
+ connection = @pipeclient.check_pending
248
+
249
+ connection.progress do |data|
250
+ @sync.synchronize {
251
+ @log << data
252
+ }
253
+ connection.write('pong')
254
+ end
255
+ connection.start_read
256
+ connection.finally do
257
+ @pipeclient.close
258
+ @reactor2.stop
259
+ @reactor.stop
260
+ end
261
+ end
262
+
263
+ @pipeclient.start_read
264
+ end
265
+ end
266
+ end
267
+ }
268
+
269
+ expect(@general_failure).to eq([])
270
+ expect(@log).to eq(['ping', 'pong'])
271
+ end
272
+ end
data/spec/test.sh ADDED
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+ echo $SOME_VAR
3
+ echo $1
4
+ echo $2
data/spec/test_fail.sh ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+ ech $SOME_VAR
3
+ exit 1
data/spec/test_read.sh ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+ read year
3
+ echo "you entered $year - sweet"
@@ -0,0 +1,14 @@
1
+ require 'mt-libuv'
2
+
3
+ describe MTLibuv::Timer do
4
+ describe 'setting properties' do
5
+ it "should allow repeat to be set" do
6
+ @reactor = MTLibuv::Reactor.new
7
+ @reactor.run { |logger|
8
+ @timer = @reactor.timer
9
+ @timer.repeat = 5
10
+ expect(@timer.repeat).to eq(5)
11
+ }
12
+ end
13
+ end
14
+ end
data/spec/udp_spec.rb ADDED
@@ -0,0 +1,73 @@
1
+ require 'mt-libuv'
2
+ require 'thread'
3
+
4
+
5
+ describe MTLibuv::UDP do
6
+ before :each do
7
+ @log = []
8
+ @general_failure = []
9
+
10
+ @reactor = MTLibuv::Reactor.new
11
+ @server = @reactor.udp
12
+ @client = @reactor.udp
13
+ @timeout = @reactor.timer do
14
+ @reactor.stop
15
+ @general_failure << "test timed out"
16
+ end
17
+ @timeout.start(5000)
18
+
19
+ @reactor.notifier do |error, context|
20
+ begin
21
+ @general_failure << "Log called: #{context}\n#{error.message}\n#{error.backtrace.join("\n") if error.backtrace}\n"
22
+ rescue Exception => e
23
+ @general_failure << "error in logger #{e.inspect}"
24
+ end
25
+ end
26
+
27
+ @reactor.all(@server, @client, @timeout).catch do |reason|
28
+ @general_failure << reason.inspect
29
+ end
30
+ end
31
+
32
+ describe 'basic client server' do
33
+ it "should send a ping and return a pong", :network => true do
34
+ @reactor.run { |reactor|
35
+ @server.bind('127.0.0.1', 34567)
36
+ @server.progress do |data, ip, port, server|
37
+ @log << data
38
+ server.send(ip, port, 'pong')
39
+ end
40
+ @server.start_read
41
+
42
+ # catch errors
43
+ @server.catch do |reason|
44
+ @general_failure << reason.inspect
45
+ end
46
+
47
+
48
+ # connect client to server
49
+ @client.bind('127.0.0.1', 34568)
50
+ @client.progress do |data, ip, port, client|
51
+ @log << data
52
+ client.close
53
+ end
54
+ @client.start_read
55
+ @client.send('127.0.0.1', 34567, 'ping')
56
+
57
+ # catch errors
58
+ @client.catch do |reason|
59
+ @general_failure << reason.inspect
60
+ end
61
+
62
+ # close the handle
63
+ @client.finally do
64
+ @server.close
65
+ @reactor.stop
66
+ end
67
+ }
68
+
69
+ expect(@log).to eq(['ping', 'pong'])
70
+ expect(@general_failure).to eq([])
71
+ end
72
+ end
73
+ end
data/spec/zen_spec.rb ADDED
@@ -0,0 +1,34 @@
1
+ require 'mt-libuv'
2
+
3
+
4
+ describe MTLibuv::Listener do
5
+ it "should ensure there are no remaining object references in callbacks", network: true do
6
+ require 'objspace'
7
+
8
+ checked = []
9
+
10
+ # These are created by loop objects and are never cleaned up
11
+ # This is OK as the loops are expected to execute for the life of the application
12
+ except = [::MTLibuv::Async, ::MTLibuv::Timer, ::MTLibuv::Prepare, ::MTLibuv::Signal]
13
+
14
+ ObjectSpace.each_object(Class) do |cls|
15
+ next unless cls.ancestors.include? ::MTLibuv::Handle
16
+ next if checked.include? cls
17
+ checked << cls
18
+
19
+ values = cls.callback_lookup.values
20
+ values.select! {|val| except.include?(val.class) ? false : val.class }
21
+
22
+ if values.length > 0
23
+ puts "\nMemory Leak in #{cls} with #{values.length} left over objects"
24
+ puts "Checked #{checked.length} classes, objects are:"
25
+ values.each do |val|
26
+ puts "\n#{val}\n"
27
+ end
28
+ raise 'Free the machines!'
29
+ end
30
+ end
31
+
32
+ expect(checked.length).to be > 3
33
+ end
34
+ end